Java tutorial
/* * Copyright (C) 2010-2011 The Project Lombok Authors. * * 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.ast.ecj; import static lombok.ast.ConversionPositionInfo.setConversionPositionInfo; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import lombok.ast.BinaryOperator; import lombok.ast.KeywordModifier; import lombok.ast.Node; import lombok.ast.Position; import lombok.ast.RawListAccessor; import lombok.ast.StrictListAccessor; import lombok.ast.UnaryOperator; import lombok.ast.VariableDefinition; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ArrayReference; import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; import org.eclipse.jdt.internal.compiler.ast.AssertStatement; import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.BinaryExpression; import org.eclipse.jdt.internal.compiler.ast.Block; import org.eclipse.jdt.internal.compiler.ast.BreakStatement; import org.eclipse.jdt.internal.compiler.ast.CaseStatement; import org.eclipse.jdt.internal.compiler.ast.CastExpression; import org.eclipse.jdt.internal.compiler.ast.CharLiteral; import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; import org.eclipse.jdt.internal.compiler.ast.Clinit; import org.eclipse.jdt.internal.compiler.ast.CombinedBinaryExpression; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment; import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.ContinueStatement; import org.eclipse.jdt.internal.compiler.ast.DoStatement; import org.eclipse.jdt.internal.compiler.ast.DoubleLiteral; import org.eclipse.jdt.internal.compiler.ast.EmptyStatement; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ExtendedStringLiteral; import org.eclipse.jdt.internal.compiler.ast.FalseLiteral; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.FloatLiteral; import org.eclipse.jdt.internal.compiler.ast.ForStatement; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression; import org.eclipse.jdt.internal.compiler.ast.IntLiteral; import org.eclipse.jdt.internal.compiler.ast.IntLiteralMinValue; import org.eclipse.jdt.internal.compiler.ast.Javadoc; import org.eclipse.jdt.internal.compiler.ast.LabeledStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.LongLiteral; import org.eclipse.jdt.internal.compiler.ast.LongLiteralMinValue; import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation; import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression; import org.eclipse.jdt.internal.compiler.ast.OperatorIds; import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.PostfixExpression; import org.eclipse.jdt.internal.compiler.ast.PrefixExpression; import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation; import org.eclipse.jdt.internal.compiler.ast.SuperReference; import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; import org.eclipse.jdt.internal.compiler.ast.TrueLiteral; import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.UnaryExpression; import org.eclipse.jdt.internal.compiler.ast.UnionTypeReference; import org.eclipse.jdt.internal.compiler.ast.WhileStatement; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; public class EcjTreeConverter { private enum FlagKey { IMPORTDECLARATION_IS_PACKAGE, NAMEREFERENCE_IS_TYPE, AS_STATEMENT, AS_DEFINITION, AS_ENUM, NO_VARDECL_FOLDING, } private List<? extends Node> result = null; private Map<FlagKey, Object> params = ImmutableMap.of(); private String rawInput; private static final Comparator<ASTNode> ASTNODE_ORDER = new Comparator<ASTNode>() { @Override public int compare(ASTNode nodeOne, ASTNode nodeTwo) { return nodeOne.sourceStart - nodeTwo.sourceStart; } }; private boolean hasFlag(FlagKey key) { return params.containsKey(key); } @SuppressWarnings("unused") private Object getFlag(FlagKey key) { return params.get(key); } public List<? extends Node> getAll() { return result; } public Node get() { if (result.isEmpty()) { return null; } if (result.size() == 1) { return result.get(0); } throw new RuntimeException("Expected only one result but got " + result.size()); } private void set(ASTNode node, Node value) { if (result != null) throw new IllegalStateException("result is already set"); if (value instanceof lombok.ast.Expression && hasFlag(FlagKey.AS_STATEMENT)) { lombok.ast.ExpressionStatement stat = new lombok.ast.ExpressionStatement(); stat.astExpression((lombok.ast.Expression) value); int start = node.sourceStart; int end = node.sourceEnd; try { end = (Integer) node.getClass().getField("statementEnd").get(node); } catch (Exception e) { // Not all these classes may have a statementEnd. } set(node, stat.setPosition(toPosition(start, end))); return; } if (value instanceof lombok.ast.Expression) { int parenCount = (node.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT; for (int i = 0; i < parenCount; i++) { ((lombok.ast.Expression) value).astParensPositions().add(value.getPosition()); } } List<Node> result = Lists.newArrayList(); if (value != null) result.add(value); this.result = result; if (value != null) value.setNativeNode(node); } @SuppressWarnings("unused") private void set(ASTNode node, List<? extends Node> values) { if (values.isEmpty()) System.err.printf("Node '%s' (%s) did not produce any results\n", node, node.getClass().getSimpleName()); if (result != null) throw new IllegalStateException("result is already set"); this.result = values; for (Node value : values) { value.setNativeNode(node); } } private Node toTree(ASTNode node, FlagKey... keys) { Map<FlagKey, Object> map = Maps.newEnumMap(FlagKey.class); for (FlagKey key : keys) map.put(key, key); return toTree(node, map); } private Node toTree(ASTNode node, Map<FlagKey, Object> params) { if (node == null) return null; EcjTreeConverter newConverter = new EcjTreeConverter(); if (params != null) newConverter.params = params; newConverter.visit(rawInput, node); try { return newConverter.get(); } catch (RuntimeException e) { System.err.printf("Node '%s' (%s) did not produce any results\n", node, node.getClass().getSimpleName()); throw e; } } private void setConversionStructInfo(Node lombokNode, String key) { setConversionPositionInfo(lombokNode, key, Position.UNPLACED); } private void fillList(ASTNode[] nodes, RawListAccessor<?, ?> list, FlagKey... keys) { Map<FlagKey, Object> map = Maps.newEnumMap(FlagKey.class); for (FlagKey key : keys) map.put(key, key); fillList(nodes, list, map); } private void fillList(ASTNode[] nodes, RawListAccessor<?, ?> list, Map<FlagKey, Object> params) { if (nodes == null) return; // int i, j; is represented with multiple AVDs, but in lombok.ast, it's 1 node. We need to // gather up sequential AVD nodes, check if the start position of each type is equal, and convert // them to one VariableDefinition by calling a special method. java.util.List<AbstractVariableDeclaration> varDeclQueue = new ArrayList<AbstractVariableDeclaration>(); boolean fold = !params.containsKey(FlagKey.NO_VARDECL_FOLDING); for (ASTNode node : nodes) { if ((node instanceof FieldDeclaration || node instanceof LocalDeclaration) && ((AbstractVariableDeclaration) node).type != null) { if (fold && (varDeclQueue.isEmpty() || varDeclQueue .get(0).type.sourceStart == ((AbstractVariableDeclaration) node).type.sourceStart)) { varDeclQueue.add((AbstractVariableDeclaration) node); continue; } else { if (!varDeclQueue.isEmpty()) list.addToEnd(toVariableDefinition(varDeclQueue, params)); varDeclQueue.clear(); varDeclQueue.add((AbstractVariableDeclaration) node); continue; } } if (!varDeclQueue.isEmpty()) list.addToEnd(toVariableDefinition(varDeclQueue, params)); varDeclQueue.clear(); list.addToEnd(toTree(node, params)); } if (!varDeclQueue.isEmpty()) list.addToEnd(toVariableDefinition(varDeclQueue, params)); } private void fillUtilityList(List<ASTNode> list, ASTNode... nodes) { if (nodes == null || nodes.length == 0) return; for (ASTNode statement : nodes) if (statement != null) list.add(statement); } public void visit(String rawInput, ASTNode node) { this.rawInput = rawInput; visitor.visitEcjNode(node); } private Node toVariableDefinition(List<AbstractVariableDeclaration> decls, FlagKey... keys) { Map<FlagKey, Object> map = Maps.newEnumMap(FlagKey.class); for (FlagKey key : keys) map.put(key, key); return toVariableDefinition(decls, map); } private Node toVariableDefinition(List<AbstractVariableDeclaration> decls, Map<FlagKey, Object> params) { lombok.ast.VariableDefinition def = createVariableDefinition(decls, params); AbstractVariableDeclaration first = decls.get(0); def.setPosition(toPosition(first.declarationSourceStart, first.sourceEnd)); if (params.containsKey(FlagKey.AS_DEFINITION)) return def; lombok.ast.VariableDeclaration decl = new lombok.ast.VariableDeclaration(); if (first instanceof FieldDeclaration) { decl.astJavadoc((lombok.ast.Comment) toTree(((FieldDeclaration) first).javadoc)); } decl.astDefinition(def); decl.setPosition(toPosition(first.declarationSourceStart, first.declarationEnd)); return decl; } private lombok.ast.VariableDefinition createVariableDefinition(List<AbstractVariableDeclaration> decls, Map<FlagKey, Object> params) { int dims = Integer.MAX_VALUE; TypeReference winner = null; for (AbstractVariableDeclaration decl : decls) { TypeReference tr = decl.type; int newDims = tr.dimensions(); if (newDims < dims) { dims = newDims; winner = tr; } if (dims == 0) break; } AbstractVariableDeclaration first = decls.get(0); lombok.ast.VariableDefinition varDef = new lombok.ast.VariableDefinition(); varDef.astModifiers(toModifiers(first.modifiers, first.annotations, first.modifiersSourceStart, first.declarationSourceStart)); varDef.astTypeReference((lombok.ast.TypeReference) toTree(winner)); if ((first.type.bits & ASTNode.IsVarArgs) != 0) { varDef.astVarargs(true); setConversionPositionInfo(varDef, "typeref", toPosition(first.type.sourceStart, first.type.sourceEnd)); } for (AbstractVariableDeclaration decl : decls) { lombok.ast.VariableDefinitionEntry varDefEntry = new lombok.ast.VariableDefinitionEntry(); varDefEntry.setNativeNode(decl); if (first instanceof FieldDeclaration) { setConversionPositionInfo(varDefEntry, "varDeclPart1", toPosition(decl.sourceStart, ((FieldDeclaration) decl).endPart1Position)); setConversionPositionInfo(varDefEntry, "varDeclPart2", toPosition(decl.sourceStart, ((FieldDeclaration) decl).endPart2Position)); } setConversionPositionInfo(varDefEntry, "declarationSource", toPosition(decl.declarationSourceStart, decl.declarationSourceEnd)); setConversionPositionInfo(varDefEntry, "typeSourcePos", toPosition(decl.type.sourceStart, decl.type.sourceEnd)); varDefEntry.astInitializer((lombok.ast.Expression) toTree(decl.initialization)); varDefEntry.astName(toIdentifier(decl.name, decl.sourceStart, decl.sourceEnd)); int delta = decl.type.dimensions() - winner.dimensions(); varDefEntry.astArrayDimensions(delta); varDef.astVariables().addToEnd(varDefEntry); } return varDef; } private lombok.ast.Identifier toIdentifier(char[] token, long pos) { return toIdentifier(token, toPosition(pos)); } private lombok.ast.Identifier toIdentifier(char[] token, int start, int end) { return toIdentifier(token, toPosition(start, end)); } private lombok.ast.Identifier toIdentifier(char[] token, Position pos) { lombok.ast.Identifier id = lombok.ast.Identifier.of(token == null ? "" : new String(token)); id.setPosition(pos); return id; } private Position toPosition(int start, int end) { return new Position(start, end + 1); } private Position toPosition(long pos) { return new Position((int) (pos >> 32), (int) (pos & 0xFFFFFFFFL) + 1); } private long toLong(int start, int end) { return (((long) start) << 32) | (0xFFFFFFFFL & end); } private lombok.ast.Modifiers toModifiers(int modifiers, Annotation[] annotations, int start, int end) { lombok.ast.Modifiers m = new lombok.ast.Modifiers(); for (KeywordModifier mod : KeywordModifier.fromReflectModifiers(modifiers)) m.astKeywords().addToEnd(mod); fillList(annotations, m.rawAnnotations()); m.setPosition(new Position(start, end)); return m; } private lombok.ast.Block toBlock(Statement[] statements) { lombok.ast.Block block = new lombok.ast.Block(); fillList(statements, block.rawContents(), FlagKey.AS_STATEMENT); return block; } private void fillDimensions(Expression[] nodes, RawListAccessor<lombok.ast.ArrayDimension, lombok.ast.ArrayCreation> list) { if (nodes == null) return; for (Expression node : nodes) list.addToEnd(new lombok.ast.ArrayDimension().astDimension((lombok.ast.Expression) toTree(node))); } private void fillIdentifiers(char[][] tokens, long[] positions, StrictListAccessor<lombok.ast.Identifier, ?> list) { if (tokens == null) return; if (positions.length != tokens.length) throw new IllegalStateException("bug"); for (int i = 0; i < positions.length; i++) { list.addToEnd(toIdentifier(tokens[i], positions[i])); } } private <N extends lombok.ast.Node> N setPosition(ASTNode node, N lombokNode) { lombokNode.setPosition(toPosition(node.sourceStart, node.sourceEnd)); return lombokNode; } private final EcjTreeVisitor visitor = new EcjTreeVisitor() { @Override public void visitCompilationUnitDeclaration(CompilationUnitDeclaration node) { lombok.ast.CompilationUnit unit = new lombok.ast.CompilationUnit(); unit.rawPackageDeclaration(toTree(node.currentPackage, FlagKey.IMPORTDECLARATION_IS_PACKAGE)); if (node.javadoc != null) { lombok.ast.PackageDeclaration lombokJavadoc = unit.astPackageDeclaration(); if (lombokJavadoc != null) { lombokJavadoc.rawJavadoc(toTree(node.javadoc)); } } fillList(node.imports, unit.rawImportDeclarations()); TypeDeclaration[] newTypes = null; if (node.types != null && node.types.length > 0 && CharOperation.equals(EcjTreeBuilder.PACKAGE_INFO, node.types[0].name)) { newTypes = new TypeDeclaration[node.types.length - 1]; System.arraycopy(node.types, 1, newTypes, 0, node.types.length - 1); } else { newTypes = node.types; } fillList(newTypes, unit.rawTypeDeclarations()); set(node, unit); } @Override public void visitImportReference(ImportReference node) { if (hasFlag(FlagKey.IMPORTDECLARATION_IS_PACKAGE)) { lombok.ast.PackageDeclaration pkg = new lombok.ast.PackageDeclaration(); fillIdentifiers(node.tokens, node.sourcePositions, pkg.astParts()); fillList(node.annotations, pkg.rawAnnotations()); pkg.setPosition(toPosition(node.declarationSourceStart, node.declarationSourceEnd)); set(node, pkg); return; } lombok.ast.ImportDeclaration imp = new lombok.ast.ImportDeclaration(); fillIdentifiers(node.tokens, node.sourcePositions, imp.astParts()); imp.astStarImport((node.bits & ASTNode.OnDemand) != 0); imp.astStaticImport((node.modifiers & ClassFileConstants.AccStatic) != 0); imp.setPosition(toPosition(node.declarationSourceStart, node.declarationSourceEnd)); set(node, imp); } @Override public void visitInitializer(Initializer node) { if ((node.modifiers & ClassFileConstants.AccStatic) != 0) { lombok.ast.StaticInitializer staticInit = new lombok.ast.StaticInitializer(); staticInit.astBody((lombok.ast.Block) toTree(node.block)); staticInit.setPosition(toPosition(node.declarationSourceStart, node.sourceEnd)); set(node, staticInit); return; } else { lombok.ast.InstanceInitializer instanceInit = new lombok.ast.InstanceInitializer(); instanceInit.astBody((lombok.ast.Block) toTree(node.block)); set(node, setPosition(node, instanceInit)); return; } } @Override public void visitTypeDeclaration(TypeDeclaration node) { lombok.ast.TypeDeclaration decl = null; switch (TypeDeclaration.kind(node.modifiers)) { case TypeDeclaration.CLASS_DECL: { lombok.ast.ClassDeclaration cDecl = new lombok.ast.ClassDeclaration(); cDecl.rawExtending(toTree(node.superclass)); cDecl.astBody(createNormalTypeBody(node)); fillList(node.superInterfaces, cDecl.rawImplementing()); fillList(node.typeParameters, cDecl.rawTypeVariables()); decl = cDecl; break; } case TypeDeclaration.INTERFACE_DECL: { lombok.ast.InterfaceDeclaration iDecl = new lombok.ast.InterfaceDeclaration(); iDecl.astBody(createNormalTypeBody(node)); fillList(node.superInterfaces, iDecl.rawExtending()); fillList(node.typeParameters, iDecl.rawTypeVariables()); decl = iDecl; break; } case TypeDeclaration.ENUM_DECL: { lombok.ast.EnumDeclaration eDecl = new lombok.ast.EnumDeclaration(); lombok.ast.EnumTypeBody enumTypeBody = createEnumTypeBody(node); fillList(node.superInterfaces, eDecl.rawImplementing()); eDecl.astBody(enumTypeBody); decl = eDecl; break; } case TypeDeclaration.ANNOTATION_TYPE_DECL: { lombok.ast.AnnotationDeclaration aDecl = new lombok.ast.AnnotationDeclaration(); aDecl.astBody(createNormalTypeBody(node)); decl = aDecl; break; } } decl.astJavadoc((lombok.ast.Comment) toTree(node.javadoc)); decl.astModifiers(toModifiers(node.modifiers, node.annotations, node.modifiersSourceStart, node.declarationSourceStart)); decl.astName(toIdentifier(node.name, node.sourceStart, node.sourceEnd)); decl.setPosition(toPosition(node.declarationSourceStart, node.declarationSourceEnd)); set(node, decl); return; } private lombok.ast.EnumTypeBody createEnumTypeBody(TypeDeclaration node) { lombok.ast.EnumTypeBody body = new lombok.ast.EnumTypeBody(); List<ASTNode> orderedList = createOrderedMemberList(node); List<ASTNode> enumConstants = new ArrayList<ASTNode>(); if (node.fields != null) for (FieldDeclaration field : node.fields) { if (isEnumConstant(field)) enumConstants.add(field); } fillList(orderedList.toArray(new ASTNode[0]), body.rawMembers()); fillList(enumConstants.toArray(new ASTNode[0]), body.rawConstants(), FlagKey.AS_ENUM); body.setPosition(toPosition(node.bodyStart - 1, node.bodyEnd)); return body; } private boolean isEnumConstant(FieldDeclaration field) { return field.type == null && !(field instanceof Initializer); } private List<ASTNode> createOrderedMemberList(TypeDeclaration node) { List<ASTNode> orderedList = new ArrayList<ASTNode>(); List<ASTNode> nonEnumConstants = new ArrayList<ASTNode>(); if (node.fields != null) for (FieldDeclaration field : node.fields) { if (!isEnumConstant(field)) nonEnumConstants.add(field); } fillUtilityList(orderedList, nonEnumConstants.toArray(new ASTNode[0])); fillUtilityList(orderedList, node.methods); fillUtilityList(orderedList, node.memberTypes); Collections.sort(orderedList, ASTNODE_ORDER); return orderedList; } private lombok.ast.NormalTypeBody createNormalTypeBody(TypeDeclaration node) { lombok.ast.NormalTypeBody body = new lombok.ast.NormalTypeBody(); List<ASTNode> orderedList = createOrderedMemberList(node); fillList(orderedList.toArray(new ASTNode[0]), body.rawMembers()); body.setPosition(toPosition(node.bodyStart - 1, node.bodyEnd)); return body; } @Override public void visitTypeParameter(TypeParameter node) { lombok.ast.TypeVariable var = new lombok.ast.TypeVariable(); var.astName(toIdentifier(node.name, node.sourceStart, node.sourceEnd)); var.astExtending().addToEnd((lombok.ast.TypeReference) toTree(node.type)); fillList(node.bounds, var.rawExtending()); setPosition(node, var); set(node, var); } @Override public void visitEmptyStatement(EmptyStatement node) { lombok.ast.EmptyStatement statement = new lombok.ast.EmptyStatement(); setPosition(node, statement); set(node, statement); } @Override public void visitLocalDeclaration(LocalDeclaration node) { set(node, toVariableDefinition(Arrays.<AbstractVariableDeclaration>asList(node), params)); } // TODO make sure we have a test for: private Object someField = new AICL() {}; @Override public void visitFieldDeclaration(FieldDeclaration node) { if (hasFlag(FlagKey.AS_ENUM)) { if (node.initialization instanceof AllocationExpression) { handleEnumConstant(node); } else { // Even just public enum c {A, B, C}; has 'new A()' as allocation expression - so this can't happen. set(node, (Node) null); } return; } set(node, toVariableDefinition(Arrays.<AbstractVariableDeclaration>asList(node))); } @Override public void visitFieldReference(FieldReference node) { lombok.ast.Select select = new lombok.ast.Select(); select.astIdentifier(toIdentifier(node.token, node.nameSourcePosition)); select.astOperand((lombok.ast.Expression) toTree(node.receiver)); set(node, setPosition(node, select)); } private void handleEnumConstant(FieldDeclaration node) { AllocationExpression init = (AllocationExpression) node.initialization; lombok.ast.EnumConstant constant = new lombok.ast.EnumConstant(); constant.astJavadoc((lombok.ast.Comment) toTree(node.javadoc)); constant.astName(toIdentifier(node.name, node.sourceStart, node.sourceEnd)); fillList(init.arguments, constant.rawArguments()); fillList(node.annotations, constant.rawAnnotations()); if (node.initialization instanceof QualifiedAllocationExpression) { QualifiedAllocationExpression qualifiedNode = ((QualifiedAllocationExpression) node.initialization); lombok.ast.NormalTypeBody body = createNormalTypeBody(qualifiedNode.anonymousType); // No idea why this is necessary, but that's why we have unit tests. body.setPosition(new Position(body.getPosition().getStart(), body.getPosition().getEnd() + 1)); constant.astBody(body); } setConversionPositionInfo(constant, "declarationSource", toPosition(node.declarationSourceStart, node.declarationSourceEnd)); constant.setPosition(toPosition(node.declarationSourceStart, node.declarationEnd)); set(node, constant); } @Override public void visitBlock(Block node) { lombok.ast.Block lombokNode = toBlock(node.statements); set(node, setPosition(node, lombokNode)); } @Override public void visitSingleTypeReference(SingleTypeReference node) { lombok.ast.TypeReference ref = new lombok.ast.TypeReference(); ref.astParts().addToEnd(createSingleTypeReferencePart(node)); setPosition(node, ref); set(node, ref); } private lombok.ast.TypeReferencePart createSingleTypeReferencePart(SingleTypeReference node) { lombok.ast.TypeReferencePart part = new lombok.ast.TypeReferencePart(); part.astIdentifier(toIdentifier(node.token, node.sourceStart, node.sourceEnd)); part.setPosition(part.astIdentifier().getPosition()); return part; } private void fillTypeReferenceParts(char[][] tokens, long[] positions, StrictListAccessor<lombok.ast.TypeReferencePart, ?> list) { if (tokens == null) return; if (tokens.length != positions.length) throw new IllegalStateException("bug"); for (int i = 0; i < tokens.length; i++) { lombok.ast.TypeReferencePart part = new lombok.ast.TypeReferencePart(); part.astIdentifier(toIdentifier(tokens[i], positions[i])); list.addToEnd(part); } } @Override public void visitQualifiedTypeReference(QualifiedTypeReference node) { lombok.ast.TypeReference ref = new lombok.ast.TypeReference(); fillTypeReferenceParts(node.tokens, node.sourcePositions, ref.astParts()); set(node, ref); } private void fillTypeReferenceParts(char[][] tokens, long[] positions, TypeReference[][] typeArguments, StrictListAccessor<lombok.ast.TypeReferencePart, ?> list) { if (tokens == null) return; if (tokens.length != positions.length) throw new IllegalStateException("bug"); for (int i = 0; i < typeArguments.length; i++) { TypeReference[] typeReferences = typeArguments[i]; lombok.ast.TypeReferencePart part = createTypeReferencePart(tokens[i], positions[i], typeReferences); list.addToEnd(part); } } private lombok.ast.TypeReferencePart createTypeReferencePart(char[] token, long pos) { return createTypeReferencePart(token, pos, null); } private lombok.ast.TypeReferencePart createTypeReferencePart(char[] token, long pos, TypeReference[] typeReferences) { lombok.ast.TypeReferencePart part = new lombok.ast.TypeReferencePart(); part.astIdentifier(toIdentifier(token, pos)); if (typeReferences != null) fillList(typeReferences, part.rawTypeArguments()); part.setPosition(toPosition(pos)); return part; } @Override public void visitParameterizedQualifiedTypeReference(ParameterizedQualifiedTypeReference node) { lombok.ast.TypeReference ref = new lombok.ast.TypeReference(); ref.astArrayDimensions(node.dimensions()); fillTypeReferenceParts(node.tokens, node.sourcePositions, node.typeArguments, ref.astParts()); set(node, setPosition(node, ref)); } @Override public void visitWildcard(Wildcard node) { lombok.ast.TypeReference ref = (lombok.ast.TypeReference) toTree(node.bound); if (ref == null) ref = new lombok.ast.TypeReference(); switch (node.kind) { case Wildcard.UNBOUND: ref.astWildcard(lombok.ast.WildcardKind.UNBOUND); break; case Wildcard.EXTENDS: ref.astWildcard(lombok.ast.WildcardKind.EXTENDS); break; case Wildcard.SUPER: ref.astWildcard(lombok.ast.WildcardKind.SUPER); } setPosition(node, ref); set(node, ref); } @Override public void visitParameterizedSingleTypeReference(ParameterizedSingleTypeReference node) { lombok.ast.TypeReference ref = new lombok.ast.TypeReference(); lombok.ast.TypeReferencePart part = new lombok.ast.TypeReferencePart(); part.astIdentifier(toIdentifier(node.token, node.sourceStart, node.sourceEnd)); ref.astParts().addToEnd(part); fillList(node.typeArguments, part.rawTypeArguments()); ref.astArrayDimensions(node.dimensions()); set(node, setPosition(node, ref)); } @Override public void visitArrayTypeReference(ArrayTypeReference node) { lombok.ast.TypeReference ref = new lombok.ast.TypeReference(); ref.astArrayDimensions(((node.bits & ASTNode.IsVarArgs) == 0) ? node.dimensions : node.dimensions - 1); lombok.ast.TypeReferencePart part = new lombok.ast.TypeReferencePart(); part.astIdentifier(toIdentifier(node.token, node.sourceStart, node.sourceEnd)); ref.astParts().addToEnd(part); set(node, setPosition(node, ref)); } @Override public void visitArrayQualifiedTypeReference(ArrayQualifiedTypeReference node) { lombok.ast.TypeReference ref = new lombok.ast.TypeReference(); fillTypeReferenceParts(node.tokens, node.sourcePositions, ref.astParts()); ref.astArrayDimensions(node.dimensions()); set(node, setPosition(node, ref)); } private lombok.ast.Node addUnaryMinusAsParent(boolean condition, lombok.ast.Expression expression) { if (condition) { return new lombok.ast.UnaryExpression().astOperand(expression) .astOperator(UnaryOperator.UNARY_MINUS); } return expression; } @Override public void visitIntLiteral(IntLiteral node) { String rawValue = String.valueOf(node.source()); boolean negative = rawValue.startsWith("-"); lombok.ast.IntegralLiteral integral = new lombok.ast.IntegralLiteral() .rawValue(negative ? rawValue.substring(1) : rawValue); set(node, setPosition(node, addUnaryMinusAsParent(negative, integral))); } @Override public void visitIntLiteralMinValue(IntLiteralMinValue node) { visitIntLiteral(node); } @Override public void visitLongLiteral(LongLiteral node) { String rawValue = String.valueOf(node.source()); boolean negative = rawValue.startsWith("-"); lombok.ast.IntegralLiteral integral = new lombok.ast.IntegralLiteral() .rawValue(negative ? rawValue.substring(1) : rawValue); set(node, setPosition(node, addUnaryMinusAsParent(negative, integral))); } @Override public void visitLongLiteralMinValue(LongLiteralMinValue node) { visitLongLiteral(node); } @Override public void visitFloatLiteral(FloatLiteral node) { set(node, setPosition(node, new lombok.ast.FloatingPointLiteral().rawValue(String.valueOf(node.source())))); } @Override public void visitDoubleLiteral(DoubleLiteral node) { set(node, setPosition(node, new lombok.ast.FloatingPointLiteral().rawValue(String.valueOf(node.source())))); } @Override public void visitTrueLiteral(TrueLiteral node) { set(node, setPosition(node, new lombok.ast.BooleanLiteral().astValue(true))); } @Override public void visitFalseLiteral(FalseLiteral node) { set(node, setPosition(node, new lombok.ast.BooleanLiteral().astValue(false))); } @Override public void visitNullLiteral(NullLiteral node) { set(node, setPosition(node, new lombok.ast.NullLiteral())); } @Override public void visitCharLiteral(CharLiteral node) { set(node, setPosition(node, new lombok.ast.CharLiteral().rawValue(String.valueOf(node.source())))); } @Override public void visitStringLiteral(StringLiteral node) { set(node, setPosition(node, new lombok.ast.StringLiteral().astValue(String.valueOf(node.source())))); } @Override public void visitStringLiteralConcatenation(StringLiteralConcatenation node) { Node lombokAggregator = null; if (node.literals != null) { for (int i = 0; i < node.counter; i++) { Node lombokElemNode = toTree(node.literals[i]); if (lombokAggregator != null) { Position newPos = lombokElemNode.getPosition().withoutGeneratedBy(); lombokAggregator = new lombok.ast.BinaryExpression().astOperator(BinaryOperator.PLUS) .rawLeft(lombokAggregator).rawRight(lombokElemNode); lombokAggregator.setPosition(newPos); } else { lombokAggregator = lombokElemNode; } } } set(node, setPosition(node, lombokAggregator)); } @Override public void visitExtendedStringLiteral(ExtendedStringLiteral node) { // While there's a node for it, this node has no further information about the separate parts, // so we are forced to produce a single string literal. visitStringLiteral(node); } @Override public void visitSingleNameReference(SingleNameReference node) { if (hasFlag(FlagKey.NAMEREFERENCE_IS_TYPE)) { set(node, setPosition(node, new lombok.ast.TypeReference().astParts() .addToEnd(createTypeReferencePart(node.token, toLong(node.sourceStart, node.sourceEnd))))); return; } set(node, setPosition(node, new lombok.ast.VariableReference() .astIdentifier(toIdentifier(node.token, node.sourceStart, node.sourceEnd)))); } TypeReference getTypeFromCast(CastExpression node) { Object expr; try { expr = CASTEXPRESSION_TYPE_FIELD.get(node); } catch (IllegalAccessException e) { throw new IllegalStateException("Lombok is not compatible with this version of eclipse", e); } if (expr instanceof QualifiedNameReference) { QualifiedNameReference name = (QualifiedNameReference) expr; return new QualifiedTypeReference(name.tokens, name.sourcePositions); } else if (expr instanceof SingleNameReference) { SingleNameReference name = (SingleNameReference) expr; return new SingleTypeReference(name.token, (long) name.sourceStart << 32 | name.sourceEnd); } else return (TypeReference) expr; } @Override public void visitCastExpression(CastExpression node) { TypeReference ref = getTypeFromCast(node); Node result = toTree(ref, FlagKey.NAMEREFERENCE_IS_TYPE); lombok.ast.Cast cast = new lombok.ast.Cast().astTypeReference((lombok.ast.TypeReference) result); cast.astOperand((lombok.ast.Expression) toTree(node.expression)); setConversionPositionInfo(cast, "type", toPosition(ref.sourceStart, ref.sourceEnd)); set(node, setPosition(node, cast)); } @Override public void visitThisReference(ThisReference node) { set(node, node.isImplicitThis() ? null : setPosition(node, new lombok.ast.This())); } @Override public void visitQualifiedThisReference(QualifiedThisReference node) { set(node, setPosition(node, new lombok.ast.This().astQualifier((lombok.ast.TypeReference) toTree(node.qualification)))); } @Override public void visitSuperReference(SuperReference node) { set(node, setPosition(node, new lombok.ast.Super())); } @Override public void visitQualifiedSuperReference(QualifiedSuperReference node) { set(node, setPosition(node, new lombok.ast.Super().astQualifier((lombok.ast.TypeReference) toTree(node.qualification)))); } @Override public void visitClassLiteralAccess(ClassLiteralAccess node) { lombok.ast.ClassLiteral literal = new lombok.ast.ClassLiteral() .astTypeReference((lombok.ast.TypeReference) toTree(node.type)); set(node, setPosition(node, literal)); } @Override public void visitArrayAllocationExpression(ArrayAllocationExpression node) { lombok.ast.ArrayCreation creation = new lombok.ast.ArrayCreation(); creation.astInitializer((lombok.ast.ArrayInitializer) toTree(node.initializer)); fillDimensions(node.dimensions, creation.rawDimensions()); creation.astComponentTypeReference((lombok.ast.TypeReference) toTree(node.type)); set(node, setPosition(node, creation)); } @Override public void visitArrayInitializer(ArrayInitializer node) { lombok.ast.ArrayInitializer init = new lombok.ast.ArrayInitializer(); fillList(node.expressions, init.rawExpressions()); set(node, setPosition(node, init)); } @Override public void visitAssignment(Assignment node) { lombok.ast.BinaryExpression bin = new lombok.ast.BinaryExpression(); bin.astLeft((lombok.ast.Expression) toTree(node.lhs)); bin.astRight(((lombok.ast.Expression) toTree(node.expression))); bin.astOperator(BinaryOperator.ASSIGN); setPosition(node, bin); set(node, bin); } @Override public void visitArrayReference(ArrayReference node) { lombok.ast.ArrayAccess access = new lombok.ast.ArrayAccess(); access.astOperand((lombok.ast.Expression) toTree(node.receiver)); access.astIndexExpression((lombok.ast.Expression) toTree(node.position)); set(node, setPosition(node, access)); } @Override public void visitUnaryExpression(UnaryExpression node) { lombok.ast.UnaryExpression unary = new lombok.ast.UnaryExpression(); int operatorId = ((node.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT); unary.astOperator(GENERIC_UNARY_OPERATORS.get(operatorId)); unary.astOperand((lombok.ast.Expression) toTree(node.expression)); set(node, setPosition(node, unary)); } @Override public void visitPrefixExpression(PrefixExpression node) { lombok.ast.UnaryExpression unary = fillUnaryOperator(node, new lombok.ast.UnaryExpression()); unary.astOperand((lombok.ast.Expression) toTree(node.lhs)); set(node, setPosition(node, unary)); } @Override public void visitPostfixExpression(PostfixExpression node) { lombok.ast.UnaryExpression unary = fillUnaryOperator(node, new lombok.ast.UnaryExpression()); unary.astOperand(((lombok.ast.Expression) toTree(node.lhs))); set(node, setPosition(node, unary)); } @Override public void visitBinaryExpression(BinaryExpression node) { lombok.ast.BinaryExpression bin = new lombok.ast.BinaryExpression(); int operatorId = ((node.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT); bin.astOperator(GENERIC_BINARY_OPERATORS.get(operatorId)); bin.astLeft(((lombok.ast.Expression) toTree(node.left))); bin.astRight(((lombok.ast.Expression) toTree(node.right))); set(node, setPosition(node, bin)); } @Override public void visitCombinedBinaryExpression(CombinedBinaryExpression node) { visitBinaryExpression(node); } @Override public void visitCompoundAssignment(CompoundAssignment node) { lombok.ast.BinaryExpression bin = new lombok.ast.BinaryExpression(); int operatorId = node.operator; bin.astOperator(ASSIGN_BINARY_OPERATORS.get(operatorId)); bin.astLeft((lombok.ast.Expression) toTree(node.lhs)); bin.astRight((lombok.ast.Expression) toTree(node.expression)); set(node, setPosition(node, bin)); } @Override public void visitEqualExpression(EqualExpression node) { visitBinaryExpression(node); } @Override public void visitInstanceOfExpression(InstanceOfExpression node) { lombok.ast.InstanceOf instanceOf = new lombok.ast.InstanceOf(); instanceOf.astObjectReference((lombok.ast.Expression) toTree(node.expression)); instanceOf.astTypeReference((lombok.ast.TypeReference) toTree(node.type)); set(node, setPosition(node, instanceOf)); } @Override public void visitAND_AND_Expression(AND_AND_Expression node) { visitBinaryExpression(node); } @Override public void visitOR_OR_Expression(OR_OR_Expression node) { visitBinaryExpression(node); } @Override public void visitConditionalExpression(ConditionalExpression node) { lombok.ast.InlineIfExpression inlineIf = new lombok.ast.InlineIfExpression() .astCondition((lombok.ast.Expression) toTree(node.condition)) .astIfTrue((lombok.ast.Expression) toTree(node.valueIfTrue)) .astIfFalse((lombok.ast.Expression) toTree(node.valueIfFalse)); set(node, setPosition(node, inlineIf)); } @Override public void visitAllocationExpression(AllocationExpression node) { lombok.ast.ConstructorInvocation constr = new lombok.ast.ConstructorInvocation(); constr.astTypeReference((lombok.ast.TypeReference) toTree(node.type)); fillList(node.arguments, constr.rawArguments()); fillList(node.typeArguments, constr.rawConstructorTypeArguments()); set(node, setPosition(node, constr)); } @Override public void visitQualifiedAllocationExpression(QualifiedAllocationExpression node) { lombok.ast.ConstructorInvocation constr = new lombok.ast.ConstructorInvocation(); constr.astTypeReference((lombok.ast.TypeReference) toTree(node.type)); if (node.anonymousType != null) { lombok.ast.NormalTypeBody body = createNormalTypeBody(node.anonymousType); setConversionPositionInfo(constr, "signature", toPosition(node.anonymousType.sourceStart, node.anonymousType.sourceEnd)); constr.astAnonymousClassBody(body); } if (node.enclosingInstance != null) { constr.rawQualifier(toTree(node.enclosingInstance)); } fillList(node.arguments, constr.rawArguments()); fillList(node.typeArguments, constr.rawConstructorTypeArguments()); set(node, setPosition(node, constr)); } private lombok.ast.Expression toSelect(char[][] tokens, long[] positions) { if (tokens.length < 2) return null; if (tokens.length != positions.length) throw new IllegalStateException("bug"); lombok.ast.Identifier current0 = toIdentifier(tokens[0], positions[0]); lombok.ast.Expression current = new lombok.ast.VariableReference().astIdentifier(current0); current.setPosition(current0.getPosition()); for (int i = 1; i < tokens.length; i++) { lombok.ast.Select select = new lombok.ast.Select() .astIdentifier(toIdentifier(tokens[i], positions[i])); select.astOperand(current); current = select; } return current; } @Override public void visitQualifiedNameReference(QualifiedNameReference node) { if (hasFlag(FlagKey.NAMEREFERENCE_IS_TYPE)) { lombok.ast.TypeReference ref = new lombok.ast.TypeReference(); fillTypeReferenceParts(node.tokens, node.sourcePositions, ref.astParts()); set(node, setPosition(node, ref)); return; } lombok.ast.Expression select = toSelect(node.tokens, node.sourcePositions); set(node, setPosition(node, select)); } @Override public void visitMessageSend(MessageSend node) { lombok.ast.MethodInvocation inv = new lombok.ast.MethodInvocation(); fillList(node.arguments, inv.rawArguments()); fillList(node.typeArguments, inv.rawMethodTypeArguments()); inv.astOperand(((lombok.ast.Expression) toTree(node.receiver))); inv.astName(toIdentifier(node.selector, node.nameSourcePosition)); setPosition(node, inv); set(node, inv); } @Override public void visitAssertStatement(AssertStatement node) { lombok.ast.Assert asrt = new lombok.ast.Assert(); asrt.astAssertion(((lombok.ast.Expression) toTree(node.assertExpression))); asrt.astMessage(((lombok.ast.Expression) toTree(node.exceptionArgument))); set(node, setPosition(node, asrt)); } @Override public void visitDoStatement(DoStatement node) { lombok.ast.DoWhile doWhile = new lombok.ast.DoWhile(); doWhile.astCondition(((lombok.ast.Expression) toTree(node.condition))); doWhile.astStatement((lombok.ast.Statement) toTree(node.action, FlagKey.AS_STATEMENT)); set(node, setPosition(node, doWhile)); } @Override public void visitForeachStatement(ForeachStatement node) { lombok.ast.ForEach forEach = new lombok.ast.ForEach(); forEach.astIterable(((lombok.ast.Expression) toTree(node.collection))); forEach.astVariable( (lombok.ast.VariableDefinition) toTree(node.elementVariable, FlagKey.AS_DEFINITION)); forEach.astStatement((lombok.ast.Statement) toTree(node.action, FlagKey.AS_STATEMENT)); set(node, setPosition(node, forEach)); } @Override public void visitIfStatement(IfStatement node) { lombok.ast.If ifStatement = new lombok.ast.If() .astCondition(((lombok.ast.Expression) toTree(node.condition))); ifStatement.astStatement((lombok.ast.Statement) toTree(node.thenStatement, FlagKey.AS_STATEMENT)); ifStatement.astElseStatement((lombok.ast.Statement) toTree(node.elseStatement, FlagKey.AS_STATEMENT)); set(node, setPosition(node, ifStatement)); } @Override public void visitForStatement(ForStatement node) { lombok.ast.For forStat = new lombok.ast.For(); forStat.astCondition(((lombok.ast.Expression) toTree(node.condition))); forStat.astStatement((lombok.ast.Statement) toTree(node.action, FlagKey.AS_STATEMENT)); fillList(node.increments, forStat.rawUpdates()); if (node.initializations != null && node.initializations.length > 0 && node.initializations[0] instanceof LocalDeclaration) { List<AbstractVariableDeclaration> decls = Lists.newArrayList(); for (Statement initialization : node.initializations) { if (initialization instanceof AbstractVariableDeclaration) decls.add((AbstractVariableDeclaration) initialization); } forStat.astVariableDeclaration( (VariableDefinition) toVariableDefinition(decls, FlagKey.AS_DEFINITION)); } else { fillList(node.initializations, forStat.rawExpressionInits()); } set(node, setPosition(node, forStat)); } @Override public void visitLabeledStatement(LabeledStatement node) { lombok.ast.LabelledStatement label = new lombok.ast.LabelledStatement(); label.astLabel(toIdentifier(node.label, node.sourceStart, node.labelEnd)); label.astStatement((lombok.ast.Statement) toTree(node.statement, FlagKey.AS_STATEMENT)); set(node, setPosition(node, label)); } @Override public void visitContinueStatement(ContinueStatement node) { lombok.ast.Continue cnt = new lombok.ast.Continue(); if (node.label != null) cnt.astLabel(toIdentifier(node.label, node.sourceStart, node.sourceEnd)); set(node, setPosition(node, cnt)); } @Override public void visitBreakStatement(BreakStatement node) { lombok.ast.Break brk = new lombok.ast.Break(); if (node.label != null) brk.astLabel(toIdentifier(node.label, node.sourceStart, node.sourceEnd)); set(node, setPosition(node, brk)); } @Override public void visitSwitchStatement(SwitchStatement node) { lombok.ast.Switch switchStat = new lombok.ast.Switch(); switchStat.astCondition((lombok.ast.Expression) toTree(node.expression)); switchStat.astBody(toBlock(node.statements)); switchStat.astBody().setPosition(toPosition(node.blockStart, node.sourceEnd)); set(node, setPosition(node, switchStat)); } @Override public void visitCaseStatement(CaseStatement node) { if (node.constantExpression == null) { lombok.ast.Default defaultStat = new lombok.ast.Default(); //TODO still have fix drunken positioning. set(node, setPosition(node, defaultStat)); return; } lombok.ast.Case caseStat = new lombok.ast.Case(); caseStat.astCondition((lombok.ast.Expression) toTree(node.constantExpression)); set(node, setPosition(node, caseStat)); } @Override public void visitSynchronizedStatement(SynchronizedStatement node) { lombok.ast.Synchronized synch = new lombok.ast.Synchronized(); synch.astLock((lombok.ast.Expression) toTree(node.expression)); synch.astBody((lombok.ast.Block) toTree(node.block)); set(node, setPosition(node, synch)); } @Override public void visitTryStatement(TryStatement node) { lombok.ast.Try tryStat = new lombok.ast.Try(); tryStat.astBody((lombok.ast.Block) toTree(node.tryBlock)); tryStat.astFinally((lombok.ast.Block) toTree(node.finallyBlock)); toCatches(node.catchArguments, node.catchBlocks, tryStat.astCatches()); set(node, setPosition(node, tryStat)); } private void toCatches(Argument[] catchArguments, Block[] catchBlocks, StrictListAccessor<lombok.ast.Catch, lombok.ast.Try> astCatches) { if (catchArguments == null || catchBlocks == null || (catchBlocks.length != catchArguments.length)) { return; } for (int i = 0; i < catchBlocks.length; i++) { lombok.ast.Catch cat = new lombok.ast.Catch(); VariableDefinition catchArg = (VariableDefinition) toTree(catchArguments[i]); catchArg.setPosition( toPosition(catchArguments[i].declarationSourceStart, catchArguments[i].sourceEnd)); cat.astExceptionDeclaration(catchArg); cat.astBody((lombok.ast.Block) toTree(catchBlocks[i])); astCatches.addToEnd(cat); } } @Override public void visitArgument(Argument node) { lombok.ast.VariableDefinition varDef = (lombok.ast.VariableDefinition) toVariableDefinition( Arrays.<AbstractVariableDeclaration>asList(node), FlagKey.NO_VARDECL_FOLDING, FlagKey.AS_DEFINITION); set(node, setPosition(node, varDef)); } @Override public void visitThrowStatement(ThrowStatement node) { lombok.ast.Throw throwStat = new lombok.ast.Throw(); throwStat.astThrowable((lombok.ast.Expression) toTree(node.exception)); set(node, setPosition(node, throwStat)); } @Override public void visitWhileStatement(WhileStatement node) { lombok.ast.While whileStat = new lombok.ast.While(); whileStat.astCondition((lombok.ast.Expression) toTree(node.condition)); whileStat.astStatement((lombok.ast.Statement) toTree(node.action, FlagKey.AS_STATEMENT)); set(node, setPosition(node, whileStat)); } @Override public void visitConstructorDeclaration(ConstructorDeclaration node) { if ((node.bits & ASTNode.IsDefaultConstructor) != 0) { set(node, (Node) null); return; } lombok.ast.ConstructorDeclaration constr = new lombok.ast.ConstructorDeclaration(); constr.astTypeName(toIdentifier(node.selector, node.sourceStart, node.sourceEnd)); lombok.ast.Block block = toBlock(node.statements); block.setPosition(toPosition(node.bodyStart - 1, node.bodyEnd + 1)); block.astContents() .addToStart((lombok.ast.Statement) toTree(node.constructorCall, FlagKey.AS_STATEMENT)); constr.astBody(block); constr.astJavadoc((lombok.ast.Comment) toTree(node.javadoc)); constr.astModifiers(toModifiers(node.modifiers, node.annotations, node.modifiersSourceStart, node.declarationSourceStart)); fillList(node.arguments, constr.rawParameters(), FlagKey.AS_DEFINITION, FlagKey.NO_VARDECL_FOLDING); fillList(node.typeParameters, constr.rawTypeVariables()); fillList(node.thrownExceptions, constr.rawThrownTypeReferences()); setConversionPositionInfo(constr, "signature", toPosition(node.sourceStart, node.sourceEnd)); constr.setPosition(toPosition(node.declarationSourceStart, node.declarationSourceEnd)); set(node, constr); } @Override public void visitExplicitConstructorCall(ExplicitConstructorCall node) { if (node.isImplicitSuper()) { set(node, (Node) null); return; } if (node.isSuperAccess()) { lombok.ast.SuperConstructorInvocation sup = new lombok.ast.SuperConstructorInvocation(); fillList(node.arguments, sup.rawArguments()); fillList(node.typeArguments, sup.rawConstructorTypeArguments()); sup.astQualifier((lombok.ast.Expression) toTree(node.qualification)); setConversionPositionInfo(sup, "typeArguments", toPosition(node.typeArgumentsSourceStart, node.sourceEnd)); set(node, setPosition(node, sup)); return; } lombok.ast.AlternateConstructorInvocation inv = new lombok.ast.AlternateConstructorInvocation(); fillList(node.arguments, inv.rawArguments()); fillList(node.typeArguments, inv.rawConstructorTypeArguments()); setConversionPositionInfo(inv, "typeArguments", toPosition(node.typeArgumentsSourceStart, node.sourceEnd)); set(node, setPosition(node, inv)); } @Override public void visitMethodDeclaration(MethodDeclaration node) { lombok.ast.MethodDeclaration decl = new lombok.ast.MethodDeclaration(); decl.astMethodName(toIdentifier(node.selector, node.sourceStart, node.sourceEnd)); decl.astJavadoc((lombok.ast.Comment) toTree(node.javadoc)); lombok.ast.Modifiers modifiers = toModifiers(node.modifiers, node.annotations, node.modifiersSourceStart, node.declarationSourceStart); decl.astModifiers(modifiers); decl.astReturnTypeReference((lombok.ast.TypeReference) toTree(node.returnType)); boolean semiColonBody = ((node.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0); if (!modifiers.isAbstract() && !node.isNative() && !semiColonBody) { lombok.ast.Block block = toBlock(node.statements); block.setPosition(toPosition(node.bodyStart - 1, node.bodyEnd + 1)); decl.astBody(block); } fillList(node.arguments, decl.rawParameters(), FlagKey.AS_DEFINITION, FlagKey.NO_VARDECL_FOLDING); fillList(node.typeParameters, decl.rawTypeVariables()); fillList(node.thrownExceptions, decl.rawThrownTypeReferences()); setConversionPositionInfo(decl, "signature", toPosition(node.sourceStart, node.sourceEnd)); decl.setPosition(toPosition(node.declarationSourceStart, node.declarationSourceEnd)); set(node, decl); } @Override public void visitAnnotationMethodDeclaration(AnnotationMethodDeclaration node) { lombok.ast.AnnotationMethodDeclaration decl = new lombok.ast.AnnotationMethodDeclaration(); decl.astMethodName(toIdentifier(node.selector, node.sourceStart, node.sourceEnd)); decl.astJavadoc((lombok.ast.Comment) toTree(node.javadoc)); decl.astModifiers(toModifiers(node.modifiers, node.annotations, node.modifiersSourceStart, node.declarationSourceStart)); decl.astReturnTypeReference((lombok.ast.TypeReference) toTree(node.returnType)); decl.astDefaultValue((lombok.ast.Expression) toTree(node.defaultValue)); setConversionPositionInfo(decl, "signature", toPosition(node.sourceStart, node.sourceEnd)); setConversionPositionInfo(decl, "extendedDimensions", new Position(node.extendedDimensions, -1)); decl.setPosition(toPosition(node.declarationSourceStart, node.declarationSourceEnd)); set(node, decl); } @Override public void visitReturnStatement(ReturnStatement node) { lombok.ast.Return returnStat = new lombok.ast.Return(); returnStat.astValue((lombok.ast.Expression) toTree(node.expression)); set(node, setPosition(node, returnStat)); } @Override public void visitClinit(Clinit node) { //currently doing nothing... set(node, (Node) null); } @Override public void visitMarkerAnnotation(MarkerAnnotation node) { lombok.ast.Annotation annot = createAnnotation(node); annot.setPosition(toPosition(node.sourceStart, node.declarationSourceEnd)); set(node, annot); } @Override public void visitSingleMemberAnnotation(SingleMemberAnnotation node) { lombok.ast.Annotation annot = createAnnotation(node); lombok.ast.AnnotationElement element = new lombok.ast.AnnotationElement(); element.astValue((lombok.ast.AnnotationValue) toTree(node.memberValue)); annot.astElements().addToEnd(element); annot.setPosition(toPosition(node.sourceStart, node.declarationSourceEnd)); set(node, annot); } @Override public void visitNormalAnnotation(NormalAnnotation node) { lombok.ast.Annotation annot = createAnnotation(node); fillList(node.memberValuePairs, annot.rawElements()); annot.setPosition(toPosition(node.sourceStart, node.declarationSourceEnd)); setConversionStructInfo(annot, "isNormalAnnotation"); set(node, annot); } private lombok.ast.Annotation createAnnotation(Annotation node) { lombok.ast.Annotation annotation = new lombok.ast.Annotation(); annotation.astAnnotationTypeReference((lombok.ast.TypeReference) toTree(node.type)); return annotation; } @Override public void visitMemberValuePair(MemberValuePair node) { lombok.ast.AnnotationElement element = new lombok.ast.AnnotationElement(); element.astName(toIdentifier(node.name, node.sourceStart, node.sourceEnd)); element.astValue((lombok.ast.AnnotationValue) toTree(node.value)); set(node, setPosition(node, element)); } @Override public void visitUnionTypeReference(UnionTypeReference node) { // For now, just use the FIRST type reference; we need the Lombok AST API // enhanced in order to properly hold all these if (node.typeReferences.length > 0) { TypeReference ref = node.typeReferences[0]; if (ref != null) { visitEcjNode(ref); } } } @Override public void visitJavadoc(Javadoc node) { if (node == null) { set(node, (Node) null); return; } lombok.ast.Comment comment = new lombok.ast.Comment(); comment.astBlockComment(true); if (rawInput != null) { comment.astContent(rawInput.substring(node.sourceStart + 2, node.sourceEnd - 1)); } else { String reconstructed = node.toString(); comment.astContent(reconstructed.substring(2, reconstructed.length() - 2)); //+2 and -2 := Strip /* and */ } set(node, setPosition(node, comment)); } private lombok.ast.UnaryExpression fillUnaryOperator(CompoundAssignment ecjNode, lombok.ast.UnaryExpression node) { if (ecjNode instanceof PrefixExpression) { return node.astOperator(UNARY_PREFIX_OPERATORS.get(ecjNode.operator)); } if (ecjNode instanceof PostfixExpression) { return node.astOperator(UNARY_POSTFIX_OPERATORS.get(ecjNode.operator)); } return node; } }; static final Field CASTEXPRESSION_TYPE_FIELD; static { try { CASTEXPRESSION_TYPE_FIELD = CastExpression.class.getDeclaredField("type"); CASTEXPRESSION_TYPE_FIELD.setAccessible(true); } catch (NoSuchFieldException e) { throw new IllegalStateException( "This version of eclipse does not have CastExpression.type. Lombok is not compatible with this version.", e); } } static final Map<Integer, UnaryOperator> UNARY_PREFIX_OPERATORS = Maps.newHashMap(); static { UNARY_PREFIX_OPERATORS.put(OperatorIds.PLUS, UnaryOperator.PREFIX_INCREMENT); UNARY_PREFIX_OPERATORS.put(OperatorIds.MINUS, UnaryOperator.PREFIX_DECREMENT); } static final Map<Integer, UnaryOperator> UNARY_POSTFIX_OPERATORS = Maps.newHashMap(); static { UNARY_POSTFIX_OPERATORS.put(OperatorIds.PLUS, UnaryOperator.POSTFIX_INCREMENT); UNARY_POSTFIX_OPERATORS.put(OperatorIds.MINUS, UnaryOperator.POSTFIX_DECREMENT); } static final Map<Integer, UnaryOperator> GENERIC_UNARY_OPERATORS = Maps.newHashMap(); static { GENERIC_UNARY_OPERATORS.put(OperatorIds.TWIDDLE, UnaryOperator.BINARY_NOT); GENERIC_UNARY_OPERATORS.put(OperatorIds.NOT, UnaryOperator.LOGICAL_NOT); GENERIC_UNARY_OPERATORS.put(OperatorIds.PLUS, UnaryOperator.UNARY_PLUS); GENERIC_UNARY_OPERATORS.put(OperatorIds.MINUS, UnaryOperator.UNARY_MINUS); } static final Map<Integer, BinaryOperator> GENERIC_BINARY_OPERATORS = Maps.newHashMap(); static { GENERIC_BINARY_OPERATORS.put(OperatorIds.OR_OR, BinaryOperator.LOGICAL_OR); GENERIC_BINARY_OPERATORS.put(OperatorIds.AND_AND, BinaryOperator.LOGICAL_AND); GENERIC_BINARY_OPERATORS.put(OperatorIds.OR, BinaryOperator.BITWISE_OR); GENERIC_BINARY_OPERATORS.put(OperatorIds.XOR, BinaryOperator.BITWISE_XOR); GENERIC_BINARY_OPERATORS.put(OperatorIds.AND, BinaryOperator.BITWISE_AND); GENERIC_BINARY_OPERATORS.put(OperatorIds.EQUAL_EQUAL, BinaryOperator.EQUALS); GENERIC_BINARY_OPERATORS.put(OperatorIds.NOT_EQUAL, BinaryOperator.NOT_EQUALS); GENERIC_BINARY_OPERATORS.put(OperatorIds.GREATER, BinaryOperator.GREATER); GENERIC_BINARY_OPERATORS.put(OperatorIds.GREATER_EQUAL, BinaryOperator.GREATER_OR_EQUAL); GENERIC_BINARY_OPERATORS.put(OperatorIds.LESS, BinaryOperator.LESS); GENERIC_BINARY_OPERATORS.put(OperatorIds.LESS_EQUAL, BinaryOperator.LESS_OR_EQUAL); GENERIC_BINARY_OPERATORS.put(OperatorIds.LEFT_SHIFT, BinaryOperator.SHIFT_LEFT); GENERIC_BINARY_OPERATORS.put(OperatorIds.RIGHT_SHIFT, BinaryOperator.SHIFT_RIGHT); GENERIC_BINARY_OPERATORS.put(OperatorIds.UNSIGNED_RIGHT_SHIFT, BinaryOperator.BITWISE_SHIFT_RIGHT); GENERIC_BINARY_OPERATORS.put(OperatorIds.PLUS, BinaryOperator.PLUS); GENERIC_BINARY_OPERATORS.put(OperatorIds.MINUS, BinaryOperator.MINUS); GENERIC_BINARY_OPERATORS.put(OperatorIds.MULTIPLY, BinaryOperator.MULTIPLY); GENERIC_BINARY_OPERATORS.put(OperatorIds.DIVIDE, BinaryOperator.DIVIDE); GENERIC_BINARY_OPERATORS.put(OperatorIds.REMAINDER, BinaryOperator.REMAINDER); } static final Map<Integer, BinaryOperator> ASSIGN_BINARY_OPERATORS = Maps.newHashMap(); static { ASSIGN_BINARY_OPERATORS.put(OperatorIds.PLUS, BinaryOperator.PLUS_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.MINUS, BinaryOperator.MINUS_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.MULTIPLY, BinaryOperator.MULTIPLY_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.DIVIDE, BinaryOperator.DIVIDE_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.REMAINDER, BinaryOperator.REMAINDER_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.AND, BinaryOperator.AND_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.XOR, BinaryOperator.XOR_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.OR, BinaryOperator.OR_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.LEFT_SHIFT, BinaryOperator.SHIFT_LEFT_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.RIGHT_SHIFT, BinaryOperator.SHIFT_RIGHT_ASSIGN); ASSIGN_BINARY_OPERATORS.put(OperatorIds.UNSIGNED_RIGHT_SHIFT, BinaryOperator.BITWISE_SHIFT_RIGHT_ASSIGN); } }