Package lombok.ast.ecj

Source Code of lombok.ast.ecj.EcjTreeConverter

/*
§ * 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();
      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);
  }
}
TOP

Related Classes of lombok.ast.ecj.EcjTreeConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.