Package lombok.ast.javac

Source Code of lombok.ast.javac.JcTreeConverter$ConvertingVisitor

/*
* 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.javac;

import static lombok.ast.ConversionPositionInfo.setConversionPositionInfo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeMap;

import lombok.val;
import lombok.ast.AlternateConstructorInvocation;
import lombok.ast.Annotation;
import lombok.ast.AnnotationDeclaration;
import lombok.ast.AnnotationElement;
import lombok.ast.AnnotationMethodDeclaration;
import lombok.ast.ArrayAccess;
import lombok.ast.ArrayCreation;
import lombok.ast.ArrayDimension;
import lombok.ast.ArrayInitializer;
import lombok.ast.Assert;
import lombok.ast.BinaryExpression;
import lombok.ast.BinaryOperator;
import lombok.ast.Block;
import lombok.ast.BooleanLiteral;
import lombok.ast.Break;
import lombok.ast.Case;
import lombok.ast.Cast;
import lombok.ast.Catch;
import lombok.ast.CharLiteral;
import lombok.ast.ClassDeclaration;
import lombok.ast.ClassLiteral;
import lombok.ast.Comment;
import lombok.ast.CompilationUnit;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.ConstructorInvocation;
import lombok.ast.Continue;
import lombok.ast.ConversionPositionInfo;
import lombok.ast.Default;
import lombok.ast.DoWhile;
import lombok.ast.EmptyDeclaration;
import lombok.ast.EmptyStatement;
import lombok.ast.EnumConstant;
import lombok.ast.EnumDeclaration;
import lombok.ast.EnumTypeBody;
import lombok.ast.Expression;
import lombok.ast.ExpressionStatement;
import lombok.ast.FloatingPointLiteral;
import lombok.ast.For;
import lombok.ast.ForEach;
import lombok.ast.ForwardingAstVisitor;
import lombok.ast.Identifier;
import lombok.ast.If;
import lombok.ast.ImportDeclaration;
import lombok.ast.InlineIfExpression;
import lombok.ast.InstanceInitializer;
import lombok.ast.InstanceOf;
import lombok.ast.IntegralLiteral;
import lombok.ast.InterfaceDeclaration;
import lombok.ast.JavadocContainer;
import lombok.ast.KeywordModifier;
import lombok.ast.LabelledStatement;
import lombok.ast.MethodDeclaration;
import lombok.ast.MethodInvocation;
import lombok.ast.Modifiers;
import lombok.ast.Node;
import lombok.ast.NormalTypeBody;
import lombok.ast.NullLiteral;
import lombok.ast.PackageDeclaration;
import lombok.ast.Position;
import lombok.ast.RawListAccessor;
import lombok.ast.Return;
import lombok.ast.Select;
import lombok.ast.StaticInitializer;
import lombok.ast.StrictListAccessor;
import lombok.ast.StringLiteral;
import lombok.ast.Super;
import lombok.ast.SuperConstructorInvocation;
import lombok.ast.Switch;
import lombok.ast.Synchronized;
import lombok.ast.This;
import lombok.ast.Throw;
import lombok.ast.Try;
import lombok.ast.TypeDeclaration;
import lombok.ast.TypeReference;
import lombok.ast.TypeReferencePart;
import lombok.ast.TypeVariable;
import lombok.ast.UnaryExpression;
import lombok.ast.UnaryOperator;
import lombok.ast.VariableDeclaration;
import lombok.ast.VariableDefinition;
import lombok.ast.VariableDefinitionEntry;
import lombok.ast.VariableReference;
import lombok.ast.While;
import lombok.ast.WildcardKind;
import lombok.javac.CommentInfo;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
import com.sun.tools.javac.tree.JCTree.JCAssert;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCAssignOp;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCatch;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCConditional;
import com.sun.tools.javac.tree.JCTree.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCForLoop;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCIf;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCParens;
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCSkip;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCSwitch;
import com.sun.tools.javac.tree.JCTree.JCSynchronized;
import com.sun.tools.javac.tree.JCTree.JCThrow;
import com.sun.tools.javac.tree.JCTree.JCTry;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;

public class JcTreeConverter {
  private enum FlagKey {
    BLOCKS_ARE_INITIALIZERS,
    SKIP_IS_DECL,
    VARDEF_IS_DEFINITION,
    NO_VARDECL_FOLDING,
    CONTAINING_TYPE_NAME,
    TYPE_REFERENCE,
    METHODS_ARE_ANNMETHODS;
  }
 
  private java.util.List<? extends Node> result;
  private Map<JCTree, Integer> endPosTable;
  private ConvertingVisitor visitor = new ConvertingVisitor();
  private Map<FlagKey, Object> params;
 
  private static final Field JCWILDCARD_KIND, JCTREE_TAG;
  private static final Method JCTREE_GETTAG;
  static {
    Field f;
    Method m;
   
    f = null;
    try {
      f = JCWildcard.class.getDeclaredField("kind");
    } catch (NoSuchFieldException e) {}
    JCWILDCARD_KIND = f;
   
    f = null;
    try {
      f = JCTree.class.getDeclaredField("tag");
    } catch (NoSuchFieldException e) {}
    JCTREE_TAG = f;
   
    m = null;
    try {
      m = JCTree.class.getDeclaredMethod("getTag");
    } catch (NoSuchMethodException e) {}
    JCTREE_GETTAG = m;
  }
 
  public JcTreeConverter() {
    this(null, null);
  }
 
  public JcTreeConverter(Map<JCTree, Integer> endPosTable, Map<FlagKey, Object> params) {
    this.endPosTable = endPosTable;
    this.params = params == null ? ImmutableMap.<FlagKey, Object>of() : params;
  }
 
  private boolean hasFlag(FlagKey key) {
    return params.containsKey(key);
  }
 
  private Object getFlag(FlagKey key) {
    return params.get(key);
  }
 
  java.util.List<? extends Node> getAll() {
    return result;
  }
 
  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(JCTree node, Node value) {
    if (result != null) throw new IllegalStateException("result is already set");
   
    if (value != null && value.getPosition().isUnplaced()) setPos(node, value);
   
    java.util.List<Node> result = Lists.newArrayList();
    if (value != null) result.add(value);
    this.result = result;
  }
 
  private Node toTree(JCTree 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(JCTree node, Map<FlagKey, Object> params) {
    if (node == null) return null;
    JcTreeConverter newConverter = new JcTreeConverter(endPosTable, params);
    node.accept(newConverter.visitor);
    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 addJavadoc(JavadocContainer container, JCModifiers mods) {
    if ((mods.flags & Flags.DEPRECATED) != 0) {
      container.astJavadoc(new Comment().astBlockComment(true).astContent("*\n * @deprecated\n "));
    }
  }
 
  private Node toVariableDefinition(java.util.List<JCVariableDecl> decls, FlagKey... keys) {
    Map<FlagKey, Object> map = Maps.newEnumMap(FlagKey.class);
    for (FlagKey key : keys) map.put(key, key);
    return toVariableDefinition(decls, map);
  }
 
  private Position getPosition(JCTree node) {
    if (node == null) return Position.UNPLACED;
    int start = node.pos;
    Integer end_ = null;
    if (endPosTable != null) end_ = endPosTable.get(node);
    int end = end_ == null ? node.getEndPosition(endPosTable) : end_;
    return new Position(start, end);
  }
 
  private Node toVariableDefinition(java.util.List<JCVariableDecl> decls, Map<FlagKey, Object> keys) {
    boolean createDeclaration = !keys.containsKey(FlagKey.VARDEF_IS_DEFINITION);
   
    if (decls == null || decls.isEmpty()) {
      VariableDefinition def = new VariableDefinition();
      return createDeclaration ? new VariableDeclaration().astDefinition(def) : def;
    }
   
    JCVariableDecl first = decls.get(0);
    int startPosFirst = first.pos;
   
    JCExpression baseType = first.vartype;
    while (baseType instanceof JCArrayTypeTree) {
      // if written as int[] a[], b; then the base Type is *NOT* a's type, but a's type with any number of JCATT's dewrapped.
      // The only way to tell the difference is by checking positions, unfortunately: If end pos of type is after start pos of decl, it's a split.
      int endPosType = baseType.getEndPosition(endPosTable);
      if (endPosType != -1 && startPosFirst != -1 && endPosType > startPosFirst) {
        baseType = ((JCArrayTypeTree) baseType).elemtype;
      } else {
        break;
      }
    }
   
    VariableDefinition def = new VariableDefinition();
    def.astModifiers((Modifiers) toTree(first.mods));
    setPos(decls.get(decls.size()-1), def);
    if (decls.size() > 1) def.setPosition(new Position(startPosFirst, def.getPosition().getEnd()));
    int baseDims = countDims(baseType);
    if ((first.mods.flags & Flags.VARARGS) != 0) {
      def.astVarargs(true);
      setConversionPositionInfo(def, "...", getPosition(baseType));
      if (baseType instanceof JCArrayTypeTree) baseType = ((JCArrayTypeTree) baseType).elemtype;
    }
    def.rawTypeReference(toTree(baseType, FlagKey.TYPE_REFERENCE));
    def.astVarargs((first.mods.flags & Flags.VARARGS) != 0);
   
    for (JCVariableDecl varDecl : decls) {
      int extraDims = countDims(varDecl.vartype) - baseDims;
      VariableDefinitionEntry entry = new VariableDefinitionEntry();
      entry.astArrayDimensions(extraDims);
      entry.astName(setPos(varDecl, new Identifier().astValue(varDecl.name.toString())));
      entry.rawInitializer(toTree(varDecl.init));
      setPos(varDecl, entry);
      if (extraDims > 0) {
        JCArrayTypeTree arrayType = (JCArrayTypeTree) varDecl.vartype;
        for (int i = 0; i < extraDims; i++) {
          if (arrayType != null) setConversionPositionInfo(entry, "[]" + (extraDims - i - 1), getPosition(arrayType));
          arrayType = arrayType.elemtype instanceof JCArrayTypeTree ? (JCArrayTypeTree) arrayType.elemtype : null;
        }
        }
      def.astVariables().addToEnd(entry);
    }
   
    if (createDeclaration) {
      VariableDeclaration decl = new VariableDeclaration().astDefinition(def);
      decl.setPosition(def.getPosition());
      addJavadoc(decl, first.mods);
      return decl;
    }
   
    return def;
  }
 
  private static int countDims(JCExpression type) {
    int dims = 0;
    while (type instanceof JCArrayTypeTree) {
      type = ((JCArrayTypeTree) type).elemtype;
      dims++;
    }
    return dims;
  }
 
  private void fillList(java.util.List<? extends JCTree> 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(java.util.List<? extends JCTree> nodes, RawListAccessor<?, ?> list, Map<FlagKey, Object> keys) {
    if (nodes == null) return;
   
    // int i, j; is represented with multiple JCVariableDeclarations, but in lombok.ast, it's 1 node. We need to
    // gather up sequential JCVD nodes, check if their modifier objects are == equal, and call a special method
    // to convert them.
    java.util.List<JCVariableDecl> varDeclQueue = new ArrayList<JCVariableDecl>();
   
    boolean fold = !keys.containsKey(FlagKey.NO_VARDECL_FOLDING);
   
    for (JCTree node : nodes) {
      if (node instanceof JCVariableDecl) {
        if (fold && (varDeclQueue.isEmpty() || varDeclQueue.get(0).mods == ((JCVariableDecl) node).mods)) {
          varDeclQueue.add((JCVariableDecl) node);
          continue;
        } else {
          if (!varDeclQueue.isEmpty()) list.addToEnd(toVariableDefinition(varDeclQueue, keys));
          varDeclQueue.clear();
          varDeclQueue.add((JCVariableDecl) node);
          continue;
        }
      }
     
      if (!varDeclQueue.isEmpty()) list.addToEnd(toVariableDefinition(varDeclQueue, keys));
      varDeclQueue.clear();
      list.addToEnd(toTree(node, keys));
    }
   
    if (!varDeclQueue.isEmpty()) list.addToEnd(toVariableDefinition(varDeclQueue, keys));
  }
 
  private static JCTree removeParens(JCTree node) {
    if (!(node instanceof JCParens)) return node;
    return ((JCParens) node).getExpression();
  }
 
  public void visit(JCCompilationUnit cu) {
    visit(cu, cu.endPositions);
  }
 
  public void visit(JCTree node, Map<JCTree, Integer> endPosTable) {
    this.endPosTable = endPosTable;
    node.accept(visitor);
  }
 
  public Node getResult() {
    return get();
  }
 
  public Node getResultWithJavadoc(java.util.List<CommentInfo> comments) {
    ListBuffer<CommentInfo> javadocs = ListBuffer.lb();
    for (CommentInfo commentInfo : comments) {
      if (commentInfo.isJavadoc()) javadocs.append(commentInfo);
    }
   
    Node result = getResult();
    if (javadocs.isEmpty()) return result;
   
    val nodePositions = new TreeMap<Integer, Node>();
    result.accept(new ForwardingAstVisitor() {
      private void addToMap(Node positionNode, Node linked) {
        if (positionNode == null) return;
       
        int start = positionNode.getPosition().getStart();
        if (start == -1) return;
       
        if (linked instanceof JavadocContainer || !nodePositions.containsKey(start)) {
          nodePositions.put(start, linked);
        }
      }
     
      private void addToMap(StrictListAccessor<?, ?> nodes, Node linked) {
        if (nodes == null) return;
       
        for (Node node : nodes) {
          addToMap(node, linked);
        }
      }
     
      @Override public boolean visitNode(Node node) {
        int start = node.getPosition().getStart();
       
        addToMap(node, node);
        try {
          if (node instanceof VariableDeclaration) {
            addToMap(((VariableDeclaration)node).astDefinition().astModifiers(), node);
            addToMap(((VariableDeclaration)node).astDefinition().astModifiers().astAnnotations(), node);
            addToMap(((VariableDeclaration)node).astDefinition().astTypeReference(), node);
            addToMap(((VariableDeclaration)node).astDefinition().astVariables().first().astName(), node);
          } else if (node instanceof TypeDeclaration) {
            addToMap(((TypeDeclaration)node).astModifiers(), node);
            addToMap(((TypeDeclaration)node).astModifiers().astAnnotations(), node);
          } else if (node instanceof MethodDeclaration) {
            addToMap(((MethodDeclaration)node).astModifiers(), node);
            addToMap(((MethodDeclaration)node).astModifiers().astAnnotations(), node);
            addToMap(((MethodDeclaration)node).astTypeVariables().first(), node);
            addToMap(((MethodDeclaration)node).astReturnTypeReference(), node);
            addToMap(((MethodDeclaration)node).astMethodName(), node);
          } else if (node instanceof ConstructorDeclaration) {
            addToMap(((ConstructorDeclaration)node).astModifiers(), node);
            addToMap(((ConstructorDeclaration)node).astModifiers().astAnnotations(), node);
            addToMap(((ConstructorDeclaration)node).astTypeVariables().first(), node);
            addToMap(((ConstructorDeclaration)node).astTypeName(), node);
          } else if (node instanceof EnumConstant) {
            addToMap(((EnumConstant)node).astName(), node);
            addToMap(((EnumConstant)node).astAnnotations(), node);
          } else if (node instanceof AnnotationMethodDeclaration) {
            addToMap(((AnnotationMethodDeclaration)node).astModifiers(), node);
            addToMap(((AnnotationMethodDeclaration)node).astModifiers().astAnnotations(), node);
            addToMap(((AnnotationMethodDeclaration)node).astReturnTypeReference(), node);
            addToMap(((AnnotationMethodDeclaration)node).astMethodName(), node);
          } else if (node instanceof PackageDeclaration) {
            addToMap(((PackageDeclaration)node).astAnnotations(), node);
          }
        } catch (NullPointerException e) {
          // Syntax errors in file - javadoc won't get linked up correctly.
        }
       
        if (node instanceof JavadocContainer || !nodePositions.containsKey(start)) {
          nodePositions.put(start, node);
        }
       
        return false;
      }
    });
   
    for (CommentInfo javadoc : javadocs) {
      try {
        Integer key = nodePositions.tailMap(javadoc.endPos).firstKey();
        Node node = nodePositions.get(key);
        if (node instanceof JavadocContainer) {
          attachJavadocToNode(javadoc, (JavadocContainer) node);
        }
      } catch (NoSuchElementException e) {
        // Then the javadoc obviously is 'floating', as its the last thing in the file.
      }
    }
   
    return result;
  }
 
  private void attachJavadocToNode(CommentInfo javadoc, JavadocContainer node) {
    String content = javadoc.content;
    if (content.startsWith("/*") && content.endsWith("*/")) content = content.substring(2, content.length() - 2);
   
    Comment comment = new Comment().astBlockComment(true).astContent(content);
    comment.setPosition(new Position(javadoc.pos, javadoc.endPos));
    node.astJavadoc(comment);
    if (!node.getPosition().isUnplaced()) {
      int oldStart = node.getPosition().getStart();
      if (oldStart == -1 || comment.getPosition().getStart() < oldStart) {
        node.setPosition(new Position(comment.getPosition().getStart(), node.getPosition().getEnd()));
      }
    }
  }
 
  private <N extends Node> N setPos(JCTree node, N astNode) {
    if (astNode != null && node != null) {
      int start = node.pos;
      Integer end_ = endPosTable.get(node);
      if (node instanceof JCUnary) end_ = node.getEndPosition(endPosTable);
      int end = end_ == null ? node.getEndPosition(endPosTable) : end_;
      if (start != com.sun.tools.javac.util.Position.NOPOS && end != com.sun.tools.javac.util.Position.NOPOS) {
        astNode.setPosition(new Position(start, end));
      }
    }
    return astNode;
  }
 
  private void fillWithIdentifiers(JCTree node, StrictListAccessor<Identifier, ?> list) {
    if (node instanceof JCIdent) {
      JCIdent id = (JCIdent) node;
      list.addToEnd(setPos(node, new Identifier().astValue(id.name.toString())));
    } else if (node instanceof JCFieldAccess) {
      JCFieldAccess sel = (JCFieldAccess) node;
      fillWithIdentifiers(sel.selected, list);
      list.addToEnd(setPos(node, new Identifier().astValue(sel.name.toString())));
    }
  }
 
  private static void setConversionStructureInfo(Node node, String key) {
    ConversionPositionInfo.setConversionPositionInfo(node, key, Position.UNPLACED);
  }
 
  private class ConvertingVisitor extends JCTree.Visitor {
    @Override public void visitTree(JCTree node) {
      throw new UnsupportedOperationException("visit" + node.getClass().getSimpleName() + " not implemented");
    }
   
    @Override public void visitTopLevel(JCCompilationUnit node) {
      CompilationUnit unit = new CompilationUnit();
      if (node.pid != null) {
        PackageDeclaration pkg = new PackageDeclaration();
        fillWithIdentifiers(node.pid, pkg.astParts());
        unit.astPackageDeclaration(setPos(node.pid, pkg));
        fillList(node.packageAnnotations, pkg.rawAnnotations());
      }
     
      for (JCTree def : node.defs) {
        if (def instanceof JCImport) {
          unit.rawImportDeclarations().addToEnd(toTree(def));
        } else {
          unit.rawTypeDeclarations().addToEnd(toTree(def, FlagKey.SKIP_IS_DECL));
        }
      }
     
      setConversionStructureInfo(unit, "converted");
      set(node, unit);
    }
   
    @Override public void visitImport(JCImport node) {
      ImportDeclaration imp = new ImportDeclaration();
      fillWithIdentifiers(node.getQualifiedIdentifier(), imp.astParts());
      Identifier last = imp.astParts().last();
      if (last != null && "*".equals(last.astValue())) {
        imp.astParts().remove(last);
        imp.astStarImport(true);
        setConversionPositionInfo(imp, ".*", last.getPosition());
      }
      imp.astStaticImport(node.isStatic());
      set(node, imp);
    }
   
    private static final long ENUM_CONSTANT_FLAGS = Flags.PUBLIC | Flags.STATIC | Flags.FINAL | Flags.ENUM;
   
    @Override public void visitClassDef(JCClassDecl node) {
      long flags = node.mods.flags;
      String name = node.getSimpleName().toString();
      TypeDeclaration typeDecl;
      Map<FlagKey, Object> flagKeyMap = Maps.newHashMap();
      flagKeyMap.put(FlagKey.CONTAINING_TYPE_NAME, name);
      flagKeyMap.put(FlagKey.BLOCKS_ARE_INITIALIZERS, FlagKey.BLOCKS_ARE_INITIALIZERS);
      flagKeyMap.put(FlagKey.SKIP_IS_DECL, FlagKey.SKIP_IS_DECL);
     
      if ((flags & (Flags.ENUM | Flags.INTERFACE)) == 0) {
        ClassDeclaration classDecl = new ClassDeclaration();
        typeDecl = classDecl;
        fillList(node.implementing, classDecl.rawImplementing(), FlagKey.TYPE_REFERENCE);
        classDecl.rawExtending(toTree(node.extending, FlagKey.TYPE_REFERENCE));
        fillList(node.typarams, classDecl.rawTypeVariables());
        NormalTypeBody body = new NormalTypeBody();
        fillList(node.defs, body.rawMembers(), flagKeyMap);
        classDecl.astBody(body);
      } else if ((flags & Flags.ANNOTATION) != 0) {
        AnnotationDeclaration annDecl = new AnnotationDeclaration();
        typeDecl = annDecl;
        NormalTypeBody body = new NormalTypeBody();
        flagKeyMap.put(FlagKey.METHODS_ARE_ANNMETHODS, FlagKey.METHODS_ARE_ANNMETHODS);
        fillList(node.defs, body.rawMembers(), flagKeyMap);
        annDecl.astBody(body);
      } else if ((flags & Flags.INTERFACE) != 0) {
        InterfaceDeclaration itfDecl = new InterfaceDeclaration();
        typeDecl = itfDecl;
        fillList(node.typarams, itfDecl.rawTypeVariables());
        fillList(node.implementing, itfDecl.rawExtending(), FlagKey.TYPE_REFERENCE);
        NormalTypeBody body = new NormalTypeBody();
        fillList(node.defs, body.rawMembers(), flagKeyMap);
        itfDecl.astBody(body);
      } else if ((flags & Flags.ENUM) != 0) {
        EnumDeclaration enumDecl = new EnumDeclaration();
        typeDecl = enumDecl;
        EnumTypeBody body = new EnumTypeBody();
        fillList(node.implementing, enumDecl.rawImplementing(), FlagKey.TYPE_REFERENCE);
        java.util.List<JCTree> defs = new ArrayList<JCTree>();
       
        for (JCTree def : node.defs) {
          if (def instanceof JCVariableDecl) {
            JCVariableDecl vd = (JCVariableDecl) def;
            if (vd.mods != null && (vd.mods.flags & ENUM_CONSTANT_FLAGS) == ENUM_CONSTANT_FLAGS) {
              // This is an enum constant, not a field of the enum class.
              EnumConstant ec = new EnumConstant();
              setPos(def, ec);
              ec.astName(new Identifier().astValue(vd.getName().toString()));
              fillList(vd.mods.annotations, ec.rawAnnotations());
              if (vd.init instanceof JCNewClass) {
                JCNewClass init = (JCNewClass) vd.init;
                fillList(init.getArguments(), ec.rawArguments());
                if (init.getClassBody() != null) {
                  NormalTypeBody constantBody = setPos(init, new NormalTypeBody());
                  fillList(init.getClassBody().getMembers(), constantBody.rawMembers());
                  ec.astBody(constantBody);
                }
                setConversionPositionInfo(ec, "newClass", getPosition(init));
              }
              body.astConstants().addToEnd(ec);
              continue;
            }
          }
         
          defs.add(def);
        }
        fillList(defs, body.rawMembers(), flagKeyMap);
        enumDecl.astBody(body);
      } else {
        throw new IllegalStateException("Unknown type declaration: " + node);
      }
     
      typeDecl.astName(new Identifier().astValue(name));
      typeDecl.astModifiers((Modifiers) toTree(node.mods));
      addJavadoc(typeDecl, node.mods);
      set(node, typeDecl);
    }
   
    @Override public void visitModifiers(JCModifiers node) {
      Modifiers m = new Modifiers();
      fillList(node.annotations, m.rawAnnotations());
      for (KeywordModifier mod : KeywordModifier.fromReflectModifiers((int) node.flags)) m.astKeywords().addToEnd(mod);
      setConversionStructureInfo(m, "converted");
      set(node, m);
    }
   
    @Override public void visitBlock(JCBlock node) {
      Node n;
      Block b = new Block();
      fillList(node.stats, b.rawContents());
      setPos(node, b);
      if (hasFlag(FlagKey.BLOCKS_ARE_INITIALIZERS)) {
        if ((node.flags & Flags.STATIC) != 0) {
          n = setPos(node, new StaticInitializer().astBody(b));
        } else {
          // For some strange reason, solitary ; in a type body are represented not as JCSkips, but as JCBlocks with no endpos. Don't ask me why!
          if (b.rawContents().isEmpty() && node.endpos == -1) {
            n = setPos(node, new EmptyDeclaration());
          } else {
            n = setPos(node, new InstanceInitializer().astBody(b));
          }
        }
      } else {
        n = b;
      }
      set(node, n);
    }
   
    @Override public void visitSkip(JCSkip node) {
      if (hasFlag(FlagKey.SKIP_IS_DECL)) {
        set(node, new EmptyDeclaration());
      } else {
        set(node, new EmptyStatement());
      }
    }
   
    @Override public void visitVarDef(JCVariableDecl node) {
      if (hasFlag(FlagKey.VARDEF_IS_DEFINITION)) {
        set(node, toVariableDefinition(Collections.singletonList(node), FlagKey.VARDEF_IS_DEFINITION));
      } else {
        set(node, toVariableDefinition(Collections.singletonList(node)));
      }
    }
   
    @Override public void visitTypeIdent(JCPrimitiveTypeTree node) {
      String primitiveType = JcTreeBuilder.PRIMITIVES.inverse().get(node.typetag);
     
      if (primitiveType == null) throw new IllegalArgumentException("Uknown primitive type tag: " + node.typetag);
     
      TypeReferencePart part = setPos(node, new TypeReferencePart().astIdentifier(setPos(node, new Identifier().astValue(primitiveType))));
     
      set(node, new TypeReference().astParts().addToEnd(part));
    }
   
    @Override public void visitIdent(JCIdent node) {
      String name = node.getName().toString();
     
      if ("this".equals(name)) {
        This t = new This();
        set(node, t);
        setConversionPositionInfo(t, "this", getPosition(node));
        return;
      }
     
      if ("super".equals(name)) {
        Super s = new Super();
        set(node, s);
        setConversionPositionInfo(s, "super", getPosition(node));
        return;
      }
     
      Identifier id = setPos(node, new Identifier().astValue(name));
     
      if (hasFlag(FlagKey.TYPE_REFERENCE)) {
        TypeReferencePart part = setPos(node, new TypeReferencePart().astIdentifier(id));
        set(node, new TypeReference().astParts().addToEnd(part));
        return;
      }
     
      set(node, new VariableReference().astIdentifier(id));
    }
   
    @Override public void visitSelect(JCFieldAccess node) {
      String name = node.getIdentifier().toString();
     
      Identifier id = setPos(node, new Identifier().astValue(name));
      Node selected = toTree(node.selected, params);
     
      if (hasFlag(FlagKey.TYPE_REFERENCE)) {
        TypeReference parent = (TypeReference) selected;
        parent.astParts().addToEnd(setPos(node, new TypeReferencePart().astIdentifier(id)));
        set(node, parent);
        return;
      }
     
      if ("this".equals(name)) {
        This t = new This();
        setConversionPositionInfo(t, "this", getPosition(node));
        set(node, t.rawQualifier(toTree(node.getExpression(), FlagKey.TYPE_REFERENCE)));
        return;
      }
     
      if ("super".equals(name)) {
        Super s = new Super();
        setConversionPositionInfo(s, "super", getPosition(node));
        set(node, s.rawQualifier(toTree(node.getExpression(), FlagKey.TYPE_REFERENCE)));
        return;
      }
     
      if ("class".equals(name)) {
        ClassLiteral c = new ClassLiteral();
        setConversionPositionInfo(c, "class", getPosition(node));
        set(node, c.rawTypeReference(toTree(node.getExpression(), FlagKey.TYPE_REFERENCE)));
        return;
      }
     
      set(node, new Select().astIdentifier(id).rawOperand(toTree(node.getExpression())));
    }
   
    @Override public void visitTypeApply(JCTypeApply node) {
      TypeReference ref = (TypeReference) toTree(node.clazz, FlagKey.TYPE_REFERENCE);
      TypeReferencePart last = ref.astParts().last();
      fillList(node.arguments, last.rawTypeArguments(), FlagKey.TYPE_REFERENCE);
      setPos(node, ref);
      setConversionPositionInfo(last, "<", getPosition(node));
      set(node, ref);
    }
   
    @Override public void visitWildcard(JCWildcard node) {
      TypeReference ref = (TypeReference) toTree(node.getBound(), FlagKey.TYPE_REFERENCE);
      if (ref == null) ref = new TypeReference();
      switch (node.getKind()) {
      case UNBOUNDED_WILDCARD:
        ref.astWildcard(WildcardKind.UNBOUND);
        break;
      case EXTENDS_WILDCARD:
        ref.astWildcard(WildcardKind.EXTENDS);
        setConversionPositionInfo(ref, "extends", getTypeBoundKindPosition(node));
        break;
      case SUPER_WILDCARD:
        ref.astWildcard(WildcardKind.SUPER);
        setConversionPositionInfo(ref, "super", getTypeBoundKindPosition(node));
        break;
      }
      set(node, ref);
    }
   
    private Position getTypeBoundKindPosition(JCWildcard node) {
      try {
        Object o = JCWILDCARD_KIND.get(node);
        if (o instanceof TypeBoundKind) {
          return getPosition((TypeBoundKind) o);
        }
      } catch (Exception e) {}
      return Position.UNPLACED;
    }
   
    private int getTag(JCTree node) {
      if (JCTREE_GETTAG != null) {
        try {
          return (Integer) JCTREE_GETTAG.invoke(node);
        } catch (Exception e) {}
      }
      try {
        return (Integer) JCTREE_TAG.get(node);
      } catch (Exception e) {
        throw new IllegalStateException("Can't get node tag");
      }
    }
   
    @Override public void visitTypeParameter(JCTypeParameter node) {
      TypeVariable var = new TypeVariable();
      var.astName(setPos(node, new Identifier().astValue(node.name.toString())));
      fillList(node.bounds, var.rawExtending(), FlagKey.TYPE_REFERENCE);
      set(node, var);
    }
   
    @Override public void visitTypeArray(JCArrayTypeTree node) {
      TypeReference ref = (TypeReference) toTree(node.getType(), FlagKey.TYPE_REFERENCE);
      int currentDim = ref.astArrayDimensions();
      ref.astArrayDimensions(currentDim + 1);
      setConversionPositionInfo(ref, "[]" + currentDim, getPosition(node));
      set(node, ref);
    }
   
    @Override public void visitLiteral(JCLiteral node) {
      Object val = node.getValue();
      boolean negative = false;
      Expression literal = null;
      switch (node.getKind()) {
      case INT_LITERAL:
        int intValue = ((Number)val).intValue();
        negative = intValue < 0;
        if (intValue == Integer.MIN_VALUE) literal = new IntegralLiteral().astIntValue(Integer.MIN_VALUE);
        else if (negative) literal = new IntegralLiteral().astIntValue(-intValue);
        else literal = new IntegralLiteral().astIntValue(intValue);
        break;
      case LONG_LITERAL:
        long longValue = ((Number)val).longValue();
        negative = longValue < 0;
        if (longValue == Long.MIN_VALUE) literal = new IntegralLiteral().astLongValue(Long.MIN_VALUE);
        else if (negative) literal = new IntegralLiteral().astLongValue(-longValue);
        else literal = new IntegralLiteral().astLongValue(longValue);
        break;
      case FLOAT_LITERAL:
        set(node, new FloatingPointLiteral().astFloatValue(((Number)val).floatValue()));
        return;
      case DOUBLE_LITERAL:
        set(node, new FloatingPointLiteral().astDoubleValue(((Number)val).doubleValue()));
        return;
      case BOOLEAN_LITERAL:
        set(node, new BooleanLiteral().astValue((Boolean)val));
        return;
      case CHAR_LITERAL:
        set(node, new CharLiteral().astValue((Character)val));
        return;
      case STRING_LITERAL:
        set(node, new StringLiteral().astValue(val == null ? "" : val.toString()));
        return;
      case NULL_LITERAL:
        set(node, new NullLiteral());
        return;
      }
     
      if (literal != null) {
        if (negative) set(node, new UnaryExpression().astOperand(setPos(node, literal)).astOperator(UnaryOperator.UNARY_MINUS));
        else set(node, literal);
      } else {
        throw new IllegalArgumentException("Unknown JCLiteral type tag:" + node.typetag);
      }
    }
   
    @Override public void visitParens(JCParens node) {
      Expression expr = (Expression) toTree(node.getExpression());
      expr.astParensPositions().add(getPosition(node));
      set(node, expr);
    }
   
    @Override public void visitTypeCast(JCTypeCast node) {
      Cast cast = new Cast();
      cast.rawOperand(toTree(node.getExpression()));
      cast.rawTypeReference(toTree(node.getType(), FlagKey.TYPE_REFERENCE));
      set(node, cast);
    }
   
    @Override public void visitUnary(JCUnary node) {
      UnaryExpression expr = new UnaryExpression();
      expr.rawOperand(toTree(node.getExpression()));
      expr.astOperator(JcTreeBuilder.UNARY_OPERATORS.inverse().get(getTag(node)));
      set(node, expr);
    }
   
    @Override public void visitBinary(JCBinary node) {
      BinaryExpression expr = new BinaryExpression();
      expr.rawLeft(toTree(node.getLeftOperand()));
      expr.rawRight(toTree(node.getRightOperand()));
      expr.astOperator(JcTreeBuilder.BINARY_OPERATORS.inverse().get(getTag(node)));
      set(node, expr);
    }
   
    @Override public void visitNewClass(JCNewClass node) {
      ConstructorInvocation inv = new ConstructorInvocation();
      fillList(node.getArguments(), inv.rawArguments());
      fillList(node.getTypeArguments(), inv.rawConstructorTypeArguments(), FlagKey.TYPE_REFERENCE);
      inv.rawTypeReference(toTree(node.getIdentifier(), FlagKey.TYPE_REFERENCE));
      inv.rawQualifier(toTree(node.getEnclosingExpression()));
      Node n = toTree(node.getClassBody());
      if (n instanceof TypeDeclaration) {
        NormalTypeBody body = ((ClassDeclaration) n).astBody();
        if (body != null) body.unparent();
        inv.rawAnonymousClassBody(setPos(node.getClassBody(), body));
      }
      set(node, inv);
    }
   
    @Override public void visitTypeTest(JCInstanceOf node) {
      InstanceOf io = new InstanceOf();
      io.rawTypeReference(toTree(node.getType(), FlagKey.TYPE_REFERENCE));
      io.rawObjectReference(toTree(node.getExpression()));
      set(node, io);
    }
   
    @Override public void visitConditional(JCConditional node) {
      InlineIfExpression iie = new InlineIfExpression();
      iie.rawCondition(toTree(node.getCondition()));
      iie.rawIfTrue(toTree(node.getTrueExpression()));
      iie.rawIfFalse(toTree(node.getFalseExpression()));
      set(node, iie);
    }
   
    @Override public void visitAssign(JCAssign node) {
      BinaryExpression expr = new BinaryExpression();
      expr.rawRight(toTree(node.getExpression()));
      expr.rawLeft(toTree(node.getVariable()));
      expr.astOperator(BinaryOperator.ASSIGN);
      set(node, expr);
    }
   
    @Override public void visitAssignop(JCAssignOp node) {
      BinaryExpression expr = new BinaryExpression();
      expr.rawRight(toTree(node.getExpression()));
      expr.rawLeft(toTree(node.getVariable()));
      expr.astOperator(JcTreeBuilder.BINARY_OPERATORS.inverse().get(getTag(node)));
      set(node, expr);
    }
   
    @Override public void visitExec(JCExpressionStatement node) {
      Node expr = toTree(node.getExpression());
      if (expr instanceof SuperConstructorInvocation || expr instanceof AlternateConstructorInvocation) {
        setConversionPositionInfo(expr, "exec", getPosition(node));
        set(node, expr);
        return;
      }
      ExpressionStatement exec = new ExpressionStatement();
      exec.rawExpression(expr);
      set(node, exec);
    }
   
    @Override public void visitApply(JCMethodInvocation node) {
      MethodInvocation inv = new MethodInvocation();
      JCTree sel = node.getMethodSelect();
      Identifier id = new Identifier();
      if (sel instanceof JCIdent) {
        String name = ((JCIdent) sel).getName().toString();
        if ("this".equals(name)) {
          AlternateConstructorInvocation aci = new AlternateConstructorInvocation();
          fillList(node.getTypeArguments(), aci.rawConstructorTypeArguments(), FlagKey.TYPE_REFERENCE);
          fillList(node.getArguments(), aci.rawArguments());
          set(node, aci);
          setConversionPositionInfo(aci, "this", getPosition(sel));
          return;
        }
       
        if ("super".equals(name)) {
          SuperConstructorInvocation sci = new SuperConstructorInvocation();
          fillList(node.getTypeArguments(), sci.rawConstructorTypeArguments(), FlagKey.TYPE_REFERENCE);
          fillList(node.getArguments(), sci.rawArguments());
          set(node, sci);
          setConversionPositionInfo(sci, "super", getPosition(sel));
          return;
        }
       
        setPos(sel, id.astValue(name));
        sel = null;
      } else if (sel instanceof JCFieldAccess) {
        String name = ((JCFieldAccess) sel).getIdentifier().toString();
        if ("super".equals(name)) {
          SuperConstructorInvocation sci = new SuperConstructorInvocation();
          fillList(node.getTypeArguments(), sci.rawConstructorTypeArguments(), FlagKey.TYPE_REFERENCE);
          fillList(node.getArguments(), sci.rawArguments());
          sci.rawQualifier(toTree(((JCFieldAccess) sel).getExpression()));
          set(node, sci);
          setConversionPositionInfo(sci, "super", getPosition(sel));
          return;
        }
        setPos(sel, id.astValue(name));
        sel = ((JCFieldAccess) sel).getExpression();
      }
      inv.astName(id).rawOperand(toTree(sel));
      fillList(node.getTypeArguments(), inv.rawMethodTypeArguments(), FlagKey.TYPE_REFERENCE);
      fillList(node.getArguments(), inv.rawArguments());
      set(node, inv);
    }
   
    @Override public void visitNewArray(JCNewArray node) {
      ArrayInitializer init = null;
     
      if (node.getInitializers() != null) {
        init = setPos(node, new ArrayInitializer());
        fillList(node.getInitializers(), init.rawExpressions());
      }
     
      if (node.getType() == null) {
        set(node, init == null ? new ArrayInitializer() : init);
        return;
      }
     
      ArrayCreation crea = new ArrayCreation();
      JCTree type = node.getType();
      java.util.List<Position> inits = Lists.newArrayList();
      while (type instanceof JCArrayTypeTree) {
        inits.add(getPosition(type));
        type = ((JCArrayTypeTree) type).getType();
      }
     
      crea.rawComponentTypeReference(toTree(type, FlagKey.TYPE_REFERENCE));
      if (node.getDimensions() != null) for (JCExpression dim : node.getDimensions()) {
        crea.astDimensions().addToEnd(setPos(dim, new ArrayDimension().rawDimension(toTree(dim))));
      }
     
      if (init != null) crea.astDimensions().addToEnd(new ArrayDimension());
     
      // new boolean [][][] {} in javac has one less dimension for some reason.
      for (Position i : inits) {
        ArrayDimension dim = new ArrayDimension();
        dim.setPosition(i);
        crea.astDimensions().addToEnd(dim);
      }
     
      crea.astInitializer(init);
      set(node, crea);
    }
   
    @Override public void visitIndexed(JCArrayAccess node) {
      ArrayAccess aa = new ArrayAccess();
      aa.rawIndexExpression(toTree(node.getIndex()));
      aa.rawOperand(toTree(node.getExpression()));
      set(node, aa);
    }
   
    @Override public void visitAssert(JCAssert node) {
      set(node, new Assert().rawAssertion(toTree(node.getCondition())).rawMessage(toTree(node.getDetail())));
    }
   
    @Override public void visitDoLoop(JCDoWhileLoop node) {
      DoWhile dw = new DoWhile();
      JCExpression cond = node.getCondition();
      setConversionPositionInfo(dw, "()", getPosition(cond));
      set(node, dw.rawCondition(toTree(removeParens(cond))).rawStatement(toTree(node.getStatement())));
    }
   
    @Override public void visitContinue(JCContinue node) {
      Continue c = new Continue();
      if (node.getLabel() != null) {
        c.astLabel(new Identifier().astValue(node.getLabel().toString()));
      }
      set(node, c);
    }
   
    @Override public void visitBreak(JCBreak node) {
      Break b = new Break();
      if (node.getLabel() != null) {
        b.astLabel(new Identifier().astValue(node.getLabel().toString()));
      }
      set(node, b);
    }
   
    @Override public void visitForeachLoop(JCEnhancedForLoop node) {
      ForEach fe = new ForEach();
      fe.rawIterable(toTree(node.getExpression()));
      fe.rawStatement(toTree(node.getStatement()));
      fe.rawVariable(toTree(node.getVariable(), FlagKey.VARDEF_IS_DEFINITION));
      set(node, fe);
    }
   
    @Override public void visitIf(JCIf node) {
      If i = new If();
      JCExpression cond = node.getCondition();
      setConversionPositionInfo(i, "()", getPosition(cond));
      i.rawCondition(toTree(removeParens(cond)));
      i.rawStatement(toTree(node.getThenStatement()));
      i.rawElseStatement(toTree(node.getElseStatement()));
      set(node, i);
    }
   
    @Override public void visitLabelled(JCLabeledStatement node) {
      Identifier lbl = new Identifier().astValue(node.getLabel().toString());
      set(node, new LabelledStatement().rawStatement(toTree(node.getStatement())).astLabel(lbl));
    }
   
    @Override public void visitForLoop(JCForLoop node) {
      For f = new For();
      f.rawCondition(toTree(node.getCondition()));
      f.rawStatement(toTree(node.getStatement()));
      for (JCExpressionStatement upd : node.getUpdate()) {
        Node updateNode = toTree(upd.getExpression());
        setConversionPositionInfo(updateNode, "exec", getPosition(upd));
        f.rawUpdates().addToEnd(updateNode);
      }
      List<JCStatement> initializers = node.getInitializer();
      // Multiple vardefs in a row need to trigger the JCVD version AND be washed through fillList to be turned into 1 VD.
      if (!initializers.isEmpty() && initializers.get(0) instanceof JCVariableDecl) {
        Block tmp = new Block();
        fillList(initializers, tmp.rawContents(), FlagKey.VARDEF_IS_DEFINITION);
        Node varDecl = tmp.rawContents().first();
        if (varDecl != null) varDecl.unparent();
        f.rawVariableDeclaration(varDecl);
      } else {
        for (JCStatement init : initializers) {
          if (init instanceof JCExpressionStatement) {
            Node initNode = toTree(((JCExpressionStatement) init).getExpression());
            setConversionPositionInfo(initNode, "exec", getPosition(init));
            f.rawExpressionInits().addToEnd(initNode);
          } else {
            f.rawExpressionInits().addToEnd(toTree(init));
          }
        }
      }
      set(node, f);
    }
   
    @Override public void visitSwitch(JCSwitch node) {
      Switch s = new Switch();
      JCExpression cond = node.getExpression();
      setConversionPositionInfo(s, "()", getPosition(cond));
      s.rawCondition(toTree(removeParens(cond)));
      Block b = new Block();
      s.astBody(b);
      for (JCCase c : node.getCases()) {
        JCExpression rawExpr = c.getExpression();
        if (rawExpr == null) b.rawContents().addToEnd(setPos(c, new Default()));
        else b.rawContents().addToEnd(setPos(c, new Case().rawCondition(toTree(rawExpr))));
        fillList(c.getStatements(), b.rawContents());
      }
      set(node, s);
    }
   
    @Override public void visitSynchronized(JCSynchronized node) {
      Synchronized s = new Synchronized();
      JCExpression cond = node.getExpression();
      setConversionPositionInfo(s, "()", getPosition(cond));
      set(node, s.rawLock(toTree(removeParens(cond))).rawBody(toTree(node.getBlock())));
    }
   
    @Override public void visitTry(JCTry node) {
      Try t = new Try();
      t.rawBody(toTree(node.getBlock()));
      t.rawFinally(toTree(node.getFinallyBlock()));
      fillList(node.getCatches(), t.rawCatches());
      set(node, t);
    }
   
    @Override public void visitCatch(JCCatch node) {
      set(node, new Catch()
          .rawExceptionDeclaration(toTree(node.getParameter(), FlagKey.VARDEF_IS_DEFINITION))
          .rawBody(toTree(node.getBlock())));
    }
   
    @Override public void visitThrow(JCThrow node) {
      set(node, new Throw().rawThrowable(toTree(node.getExpression())));
    }
   
    @Override public void visitWhileLoop(JCWhileLoop node) {
      While w = new While();
      JCExpression cond = node.getCondition();
      setConversionPositionInfo(w, "()", getPosition(cond));
      set(node, w.rawCondition(toTree(removeParens(cond))).rawStatement(toTree(node.getStatement())));
    }
   
    @Override public void visitReturn(JCReturn node) {
      set(node, new Return().rawValue(toTree(node.getExpression())));
    }
   
    @Override public void visitMethodDef(JCMethodDecl node) {
      String name = node.getName() == null ? null : node.getName().toString();
      if ("<init>".equals(name)) {
        ConstructorDeclaration cd = new ConstructorDeclaration();
        cd.astModifiers((Modifiers) toTree(node.getModifiers()));
        cd.rawBody(toTree(node.getBody()));
        fillList(node.getThrows(), cd.rawThrownTypeReferences(), FlagKey.TYPE_REFERENCE);
        fillList(node.getTypeParameters(), cd.rawTypeVariables());
        fillList(node.getParameters(), cd.rawParameters(), FlagKey.NO_VARDECL_FOLDING, FlagKey.VARDEF_IS_DEFINITION);
        String typeName = (String) getFlag(FlagKey.CONTAINING_TYPE_NAME);
        cd.astTypeName(setPos(node, new Identifier().astValue(typeName)));
        addJavadoc(cd, node.mods);
        set(node, cd);
        return;
      }
     
      if (hasFlag(FlagKey.METHODS_ARE_ANNMETHODS)) {
        AnnotationMethodDeclaration md = new AnnotationMethodDeclaration();
        md.astModifiers((Modifiers) toTree(node.getModifiers()));
        md.astMethodName(setPos(node, new Identifier().astValue(name)));
        md.rawReturnTypeReference(toTree(node.getReturnType(), FlagKey.TYPE_REFERENCE));
        md.rawDefaultValue(toTree(node.getDefaultValue()));
        addJavadoc(md, node.mods);
        set(node, md);
        return;
      }
     
      MethodDeclaration md = new MethodDeclaration();
      md.rawBody(toTree(node.getBody()));
      md.astModifiers((Modifiers) toTree(node.getModifiers()));
      md.astMethodName(setPos(node, new Identifier().astValue(name)));
      fillList(node.getThrows(), md.rawThrownTypeReferences(), FlagKey.TYPE_REFERENCE);
      fillList(node.getTypeParameters(), md.rawTypeVariables());
      fillList(node.getParameters(), md.rawParameters(), FlagKey.NO_VARDECL_FOLDING, FlagKey.VARDEF_IS_DEFINITION);
      md.rawReturnTypeReference(toTree(node.getReturnType(), FlagKey.TYPE_REFERENCE));
      addJavadoc(md, node.mods);
      set(node, md);
    }
   
    @Override public void visitAnnotation(JCAnnotation node) {
      Annotation a = new Annotation();
      a.rawAnnotationTypeReference(toTree(node.getAnnotationType(), FlagKey.TYPE_REFERENCE));
      for (JCExpression elem : node.getArguments()) {
        AnnotationElement e = new AnnotationElement();
        if (elem instanceof JCAssign) {
          JCExpression rawName = ((JCAssign) elem).getVariable();
          if (rawName instanceof JCIdent) e.astName(setPos(rawName, new Identifier().astValue(((JCIdent)rawName).getName().toString())));
          elem = ((JCAssign) elem).getExpression();
        }
        e.rawValue(toTree(elem));
        a.astElements().addToEnd(e);
      }
      set(node, a);
    }
  }
}
TOP

Related Classes of lombok.ast.javac.JcTreeConverter$ConvertingVisitor

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.