/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.devtools.j2objc.javac;
import com.google.common.collect.Lists;
import com.google.devtools.j2objc.Options;
import com.google.devtools.j2objc.ast.AbstractTypeDeclaration;
import com.google.devtools.j2objc.ast.Annotation;
import com.google.devtools.j2objc.ast.AnnotationTypeDeclaration;
import com.google.devtools.j2objc.ast.AnnotationTypeMemberDeclaration;
import com.google.devtools.j2objc.ast.ArrayAccess;
import com.google.devtools.j2objc.ast.ArrayCreation;
import com.google.devtools.j2objc.ast.ArrayInitializer;
import com.google.devtools.j2objc.ast.ArrayType;
import com.google.devtools.j2objc.ast.AssertStatement;
import com.google.devtools.j2objc.ast.Assignment;
import com.google.devtools.j2objc.ast.Block;
import com.google.devtools.j2objc.ast.BlockComment;
import com.google.devtools.j2objc.ast.BodyDeclaration;
import com.google.devtools.j2objc.ast.BooleanLiteral;
import com.google.devtools.j2objc.ast.BreakStatement;
import com.google.devtools.j2objc.ast.CastExpression;
import com.google.devtools.j2objc.ast.CatchClause;
import com.google.devtools.j2objc.ast.CharacterLiteral;
import com.google.devtools.j2objc.ast.ClassInstanceCreation;
import com.google.devtools.j2objc.ast.Comment;
import com.google.devtools.j2objc.ast.CompilationUnit;
import com.google.devtools.j2objc.ast.ConditionalExpression;
import com.google.devtools.j2objc.ast.ConstructorInvocation;
import com.google.devtools.j2objc.ast.ContinueStatement;
import com.google.devtools.j2objc.ast.CreationReference;
import com.google.devtools.j2objc.ast.DoStatement;
import com.google.devtools.j2objc.ast.EmptyStatement;
import com.google.devtools.j2objc.ast.EnhancedForStatement;
import com.google.devtools.j2objc.ast.EnumConstantDeclaration;
import com.google.devtools.j2objc.ast.EnumDeclaration;
import com.google.devtools.j2objc.ast.Expression;
import com.google.devtools.j2objc.ast.ExpressionMethodReference;
import com.google.devtools.j2objc.ast.ExpressionStatement;
import com.google.devtools.j2objc.ast.FieldAccess;
import com.google.devtools.j2objc.ast.FieldDeclaration;
import com.google.devtools.j2objc.ast.ForStatement;
import com.google.devtools.j2objc.ast.FunctionalExpression;
import com.google.devtools.j2objc.ast.IfStatement;
import com.google.devtools.j2objc.ast.InfixExpression;
import com.google.devtools.j2objc.ast.Initializer;
import com.google.devtools.j2objc.ast.InstanceofExpression;
import com.google.devtools.j2objc.ast.Javadoc;
import com.google.devtools.j2objc.ast.LabeledStatement;
import com.google.devtools.j2objc.ast.LambdaExpression;
import com.google.devtools.j2objc.ast.LineComment;
import com.google.devtools.j2objc.ast.MarkerAnnotation;
import com.google.devtools.j2objc.ast.MemberValuePair;
import com.google.devtools.j2objc.ast.MethodDeclaration;
import com.google.devtools.j2objc.ast.MethodInvocation;
import com.google.devtools.j2objc.ast.MethodReference;
import com.google.devtools.j2objc.ast.Name;
import com.google.devtools.j2objc.ast.NormalAnnotation;
import com.google.devtools.j2objc.ast.NullLiteral;
import com.google.devtools.j2objc.ast.NumberLiteral;
import com.google.devtools.j2objc.ast.PackageDeclaration;
import com.google.devtools.j2objc.ast.ParameterizedType;
import com.google.devtools.j2objc.ast.ParenthesizedExpression;
import com.google.devtools.j2objc.ast.PostfixExpression;
import com.google.devtools.j2objc.ast.PrefixExpression;
import com.google.devtools.j2objc.ast.PrimitiveType;
import com.google.devtools.j2objc.ast.PropertyAnnotation;
import com.google.devtools.j2objc.ast.QualifiedName;
import com.google.devtools.j2objc.ast.ReturnStatement;
import com.google.devtools.j2objc.ast.SimpleName;
import com.google.devtools.j2objc.ast.SimpleType;
import com.google.devtools.j2objc.ast.SingleMemberAnnotation;
import com.google.devtools.j2objc.ast.SingleVariableDeclaration;
import com.google.devtools.j2objc.ast.SourcePosition;
import com.google.devtools.j2objc.ast.Statement;
import com.google.devtools.j2objc.ast.StringLiteral;
import com.google.devtools.j2objc.ast.SuperConstructorInvocation;
import com.google.devtools.j2objc.ast.SuperFieldAccess;
import com.google.devtools.j2objc.ast.SuperMethodInvocation;
import com.google.devtools.j2objc.ast.SuperMethodReference;
import com.google.devtools.j2objc.ast.SwitchCase;
import com.google.devtools.j2objc.ast.SwitchStatement;
import com.google.devtools.j2objc.ast.SynchronizedStatement;
import com.google.devtools.j2objc.ast.ThisExpression;
import com.google.devtools.j2objc.ast.ThrowStatement;
import com.google.devtools.j2objc.ast.TreeNode;
import com.google.devtools.j2objc.ast.TreeUtil;
import com.google.devtools.j2objc.ast.TryStatement;
import com.google.devtools.j2objc.ast.Type;
import com.google.devtools.j2objc.ast.TypeDeclaration;
import com.google.devtools.j2objc.ast.TypeDeclarationStatement;
import com.google.devtools.j2objc.ast.TypeLiteral;
import com.google.devtools.j2objc.ast.TypeMethodReference;
import com.google.devtools.j2objc.ast.UnionType;
import com.google.devtools.j2objc.ast.VariableDeclaration;
import com.google.devtools.j2objc.ast.VariableDeclarationExpression;
import com.google.devtools.j2objc.ast.VariableDeclarationFragment;
import com.google.devtools.j2objc.ast.VariableDeclarationStatement;
import com.google.devtools.j2objc.ast.WhileStatement;
import com.google.devtools.j2objc.translate.OcniExtractor;
import com.google.devtools.j2objc.types.ExecutablePair;
import com.google.devtools.j2objc.util.ElementUtil;
import com.google.devtools.j2objc.util.ErrorUtil;
import com.google.devtools.j2objc.util.FileUtil;
import com.google.devtools.j2objc.util.TranslationEnvironment;
import com.google.j2objc.annotations.Property;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.Trees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.tree.DocCommentTable;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.Tag;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.Position;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.JavaFileObject;
/**
* Converts a Java AST from the JDT data structure to our J2ObjC data structure.
*/
public class TreeConverter {
private final JCTree.JCCompilationUnit unit;
private final JavacEnvironment env;
private CompilationUnit newUnit;
public static CompilationUnit convertCompilationUnit(
Options options, JavacEnvironment env, JCTree.JCCompilationUnit javacUnit) {
String sourceFilePath = getPath(javacUnit.getSourceFile());
try {
TreeConverter converter = new TreeConverter(javacUnit, env);
JavaFileObject sourceFile = javacUnit.getSourceFile();
String source = sourceFile.getCharContent(false).toString();
String mainTypeName = FileUtil.getMainTypeName(sourceFile);
converter.newUnit = new CompilationUnit(new TranslationEnvironment(options, env),
sourceFilePath, mainTypeName, source);
PackageElement pkg = javacUnit.packge != null ? javacUnit.packge : env.defaultPackage();
converter.newUnit.setPackage(
converter.convertPackage(pkg, Trees.instance(env.task())));
for (JCTree type : javacUnit.getTypeDecls()) {
TreeNode newNode = converter.convert(type);
if (newNode.getKind() != TreeNode.Kind.EMPTY_STATEMENT) {
converter.newUnit.addType((AbstractTypeDeclaration) newNode);
}
}
addOcniComments(converter.newUnit, options.jsniWarnings());
// Enable this to debug tree conversion issues, otherwise let
// TranslationProcessor.applyMutations() handle verification.
// converter.newUnit.validate();
return converter.newUnit;
} catch (Throwable e) {
ErrorUtil.fatalError(e, sourceFilePath);
return null;
}
}
private TreeConverter(JCTree.JCCompilationUnit javacUnit, JavacEnvironment javacEnv) {
unit = javacUnit;
env = javacEnv;
}
private TreeNode convert(Object obj) {
if (obj == null) {
return null;
}
JCTree node = (JCTree) obj;
TreeNode newNode = convertInner(node)
.setPosition(getPosition(node));
if (newNode instanceof Expression) {
copyConstantValue(node, (Expression) newNode);
}
return newNode;
}
private SourcePosition getPosition(JCTree node) {
int startPosition = TreeInfo.getStartPos(node);
int endPosition = TreeInfo.getEndPos(node, unit.endPositions);
int length = startPosition == Position.NOPOS || endPosition == Position.NOPOS
? 0 : endPosition - startPosition;
return getSourcePosition(startPosition, length);
}
@SuppressWarnings("fallthrough")
private TreeNode convertInner(JCTree javacNode) {
switch (javacNode.getKind()) {
default:
throw new AssertionError("Unknown node type: " + javacNode.getKind());
case ANNOTATION:
case TYPE_ANNOTATION:
return convertAnnotation((JCTree.JCAnnotation) javacNode);
case ANNOTATION_TYPE:
return convertAnnotationTypeDeclaration((JCTree.JCClassDecl) javacNode);
case ARRAY_ACCESS:
return convertArrayAccess((JCTree.JCArrayAccess) javacNode);
case ARRAY_TYPE:
return convertArrayType((JCTree.JCArrayTypeTree) javacNode);
case ASSERT:
return convertAssert((JCTree.JCAssert) javacNode);
case ASSIGNMENT:
return convertAssignment((JCTree.JCAssign) javacNode);
case BLOCK:
return convertBlock((JCTree.JCBlock) javacNode);
case BREAK:
return convertBreakStatement((JCTree.JCBreak) javacNode);
case CASE:
return convertCase((JCTree.JCCase) javacNode);
case CATCH:
return convertCatch((JCTree.JCCatch) javacNode);
case CLASS:
return convertClassDeclaration((JCTree.JCClassDecl) javacNode);
case COMPILATION_UNIT:
throw new AssertionError(
"CompilationUnit must be converted using convertCompilationUnit()");
case CONDITIONAL_EXPRESSION:
return convertConditionalExpression((JCTree.JCConditional) javacNode);
case CONTINUE:
return convertContinueStatement((JCTree.JCContinue) javacNode);
case DO_WHILE_LOOP:
return convertDoStatement((JCTree.JCDoWhileLoop) javacNode);
case EMPTY_STATEMENT:
return new EmptyStatement();
case ENHANCED_FOR_LOOP:
return convertEnhancedForStatement((JCTree.JCEnhancedForLoop) javacNode);
case ENUM:
return convertEnum((JCTree.JCClassDecl) javacNode);
case EXPRESSION_STATEMENT:
return convertExpressionStatement((JCTree.JCExpressionStatement) javacNode);
case FOR_LOOP:
return convertForLoop((JCTree.JCForLoop) javacNode);
case IDENTIFIER:
return convertIdent((JCTree.JCIdent) javacNode);
case INSTANCE_OF:
return convertInstanceOf((JCTree.JCInstanceOf) javacNode);
case INTERFACE:
return convertClassDeclaration((JCTree.JCClassDecl) javacNode);
case IF:
return convertIf((JCTree.JCIf) javacNode);
case LABELED_STATEMENT:
return convertLabeledStatement((JCTree.JCLabeledStatement) javacNode);
case LAMBDA_EXPRESSION:
return convertLambda((JCTree.JCLambda) javacNode);
case MEMBER_REFERENCE:
return convertMemberReference((JCTree.JCMemberReference) javacNode);
case MEMBER_SELECT:
return convertFieldAccess((JCTree.JCFieldAccess) javacNode);
case METHOD:
return convertMethodDeclaration((JCTree.JCMethodDecl) javacNode);
case METHOD_INVOCATION:
return convertMethodInvocation((JCTree.JCMethodInvocation) javacNode);
case NEW_ARRAY:
return convertNewArray((JCTree.JCNewArray) javacNode);
case NEW_CLASS:
return convertNewClass((JCTree.JCNewClass) javacNode);
case PARAMETERIZED_TYPE:
return convertTypeApply((JCTree.JCTypeApply) javacNode);
case PARENTHESIZED:
return convertParens((JCTree.JCParens) javacNode);
case PRIMITIVE_TYPE:
return convertPrimitiveType((JCTree.JCPrimitiveTypeTree) javacNode);
case RETURN:
return convertReturn((JCTree.JCReturn) javacNode);
case SWITCH:
return convertSwitch((JCTree.JCSwitch) javacNode);
case THROW:
return convertThrow((JCTree.JCThrow) javacNode);
case TRY:
return convertTry((JCTree.JCTry) javacNode);
case TYPE_CAST:
return convertTypeCast((JCTree.JCTypeCast) javacNode);
case VARIABLE:
return convertVariableDeclaration((JCTree.JCVariableDecl) javacNode);
case WHILE_LOOP:
return convertWhileLoop((JCTree.JCWhileLoop) javacNode);
case BOOLEAN_LITERAL:
return convertBooleanLiteral((JCTree.JCLiteral) javacNode);
case CHAR_LITERAL:
return convertCharLiteral((JCTree.JCLiteral) javacNode);
case DOUBLE_LITERAL:
case FLOAT_LITERAL:
case INT_LITERAL:
case LONG_LITERAL:
return convertNumberLiteral((JCTree.JCLiteral) javacNode);
case STRING_LITERAL:
return convertStringLiteral((JCTree.JCLiteral) javacNode);
case SYNCHRONIZED:
return convertSynchronized((JCTree.JCSynchronized) javacNode);
case NULL_LITERAL:
return new NullLiteral(((JCTree.JCLiteral) javacNode).type);
case AND:
case CONDITIONAL_AND:
case CONDITIONAL_OR:
case DIVIDE:
case EQUAL_TO:
case GREATER_THAN:
case GREATER_THAN_EQUAL:
case LEFT_SHIFT:
case LESS_THAN:
case LESS_THAN_EQUAL:
case MINUS:
case MULTIPLY:
case NOT_EQUAL_TO:
case OR:
case PLUS:
case REMAINDER:
case RIGHT_SHIFT:
case UNSIGNED_RIGHT_SHIFT:
case XOR:
return convertBinary((JCTree.JCBinary) javacNode);
case BITWISE_COMPLEMENT:
case LOGICAL_COMPLEMENT:
case PREFIX_DECREMENT:
case PREFIX_INCREMENT:
case UNARY_MINUS:
case UNARY_PLUS:
return convertPrefixExpr((JCTree.JCUnary) javacNode);
case POSTFIX_DECREMENT:
case POSTFIX_INCREMENT:
return convertPostExpr((JCTree.JCUnary) javacNode);
case AND_ASSIGNMENT:
case DIVIDE_ASSIGNMENT:
case LEFT_SHIFT_ASSIGNMENT:
case MINUS_ASSIGNMENT:
case MULTIPLY_ASSIGNMENT:
case OR_ASSIGNMENT:
case PLUS_ASSIGNMENT:
case REMAINDER_ASSIGNMENT:
case RIGHT_SHIFT_ASSIGNMENT:
case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
case XOR_ASSIGNMENT:
return convertAssignOp((JCTree.JCAssignOp) javacNode);
case OTHER: {
if (javacNode.hasTag(Tag.NULLCHK)) {
// Skip javac's nullchk operators, since j2objc provides its own.
// TODO(tball): convert to nil_chk() functions in this class, to
// always check references that javac flagged?
return convert(((JCTree.JCUnary) javacNode).arg);
}
throw new AssertionError("Unknown OTHER node, tag: " + javacNode.getTag());
}
}
}
private TreeNode convertAbstractTypeDeclaration(
JCTree.JCClassDecl node, AbstractTypeDeclaration newNode) {
convertBodyDeclaration(node, node.getModifiers(), newNode, node.sym);
List<BodyDeclaration> bodyDeclarations = new ArrayList<>();
for (JCTree bodyDecl : node.getMembers()) {
Object member = convert(bodyDecl);
if (member instanceof BodyDeclaration) { // Not true for enum constants.
bodyDeclarations.add((BodyDeclaration) member);
} else if (member instanceof Block) {
JCTree.JCBlock javacBlock = (JCTree.JCBlock) bodyDecl;
Block block = (Block) member;
bodyDeclarations.add(new Initializer(block, javacBlock.isStatic()));
}
}
return newNode
.setName(convertSimpleName(node.sym, node.sym.asType(), getNamePosition(node)))
.setTypeElement(node.sym)
.setBodyDeclarations(bodyDeclarations);
}
private TreeNode convertAnnotation(JCTree.JCAnnotation node) {
List<JCTree.JCExpression> args = node.getArguments();
String annotationName = node.getAnnotationType().toString();
boolean isPropertyAnnotation = annotationName.equals(Property.class.getSimpleName())
|| annotationName.equals(Property.class.getName());
Annotation newNode;
if (isPropertyAnnotation) {
newNode = new PropertyAnnotation()
.setAnnotationMirror(node.attribute);
if (!args.isEmpty()) {
for (String attr : ElementUtil.parsePropertyAttribute(node.attribute)) {
((PropertyAnnotation) newNode).addAttribute(attr);
}
}
} else if (args.isEmpty()) {
newNode = new MarkerAnnotation()
.setAnnotationMirror(node.attribute);
} else if (args.size() == 1) {
JCTree.JCAssign assign = (JCTree.JCAssign) args.get(0);
newNode = new SingleMemberAnnotation()
.setValue((Expression) convert(assign.rhs));
} else {
NormalAnnotation normalAnn = new NormalAnnotation();
for (JCTree.JCExpression obj : node.getArguments()) {
JCTree.JCAssign assign = (JCTree.JCAssign) obj;
Symbol sym = ((JCTree.JCIdent) assign.lhs).sym;
MemberValuePair memberPair = new MemberValuePair()
.setName(convertSimpleName(sym, sym.asType(), getPosition(assign.lhs)))
.setValue((Expression) convert(assign.rhs));
normalAnn.addValue(memberPair);
}
newNode = normalAnn;
}
return newNode
.setAnnotationMirror(node.attribute)
.setTypeName((Name) convert(node.getAnnotationType()));
}
private List<Annotation> convertAnnotations(JCTree.JCModifiers modifiers) {
List<Annotation> annotations = new ArrayList<>();
for (AnnotationTree annotation : modifiers.getAnnotations()) {
annotations.add((Annotation) convert(annotation));
}
return annotations;
}
private TreeNode convertAnnotationTypeDeclaration(JCTree.JCClassDecl node) {
AnnotationTypeDeclaration newNode = new AnnotationTypeDeclaration();
convertBodyDeclaration(node, node.getModifiers(), newNode, node.sym);
for (JCTree bodyDecl : node.getMembers()) {
if (bodyDecl.getKind() == Kind.METHOD) {
JCTree.JCMethodDecl methodDecl = (JCTree.JCMethodDecl) bodyDecl;
AnnotationTypeMemberDeclaration newMember = new AnnotationTypeMemberDeclaration()
.setDefault((Expression) convert(methodDecl.defaultValue))
.setExecutableElement(methodDecl.sym);
newMember
.setModifiers((int) methodDecl.getModifiers().flags)
.setAnnotations(convertAnnotations(methodDecl.mods))
.setJavadoc((Javadoc) getAssociatedJavaDoc(methodDecl, methodDecl.sym));
newNode.addBodyDeclaration(newMember);
} else {
newNode.addBodyDeclaration((BodyDeclaration) convert(bodyDecl));
}
}
return newNode
.setName(convertSimpleName(node.sym, node.type, getNamePosition(node)))
.setTypeElement(node.sym);
}
private TreeNode convertArrayAccess(JCTree.JCArrayAccess node) {
return new ArrayAccess()
.setArray((Expression) convert(node.getExpression()))
.setIndex((Expression) convert(node.getIndex()));
}
private TreeNode convertArrayType(JCTree.JCArrayTypeTree node) {
ArrayType newNode = new ArrayType();
Type componentType = (Type) Type.newType(node.getType().type);
return newNode
.setComponentType(componentType)
.setTypeMirror(node.type);
}
private TreeNode convertAssert(JCTree.JCAssert node) {
return new AssertStatement()
.setExpression((Expression) convert(node.getCondition()))
.setMessage((Expression) convert(node.getDetail()));
}
private TreeNode convertAssignment(JCTree.JCAssign node) {
Assignment newNode = new Assignment();
return newNode
.setOperator(Assignment.Operator.ASSIGN)
.setLeftHandSide((Expression) convert(node.getVariable()))
.setRightHandSide((Expression) convert(node.getExpression()));
}
private TreeNode convertAssignOp(JCTree.JCAssignOp node) {
Assignment newNode = new Assignment();
String operatorName = node.getOperator().getSimpleName().toString() + "=";
return newNode
.setOperator(Assignment.Operator.fromJdtOperatorName(operatorName))
.setLeftHandSide((Expression) convert(node.getVariable()))
.setRightHandSide((Expression) convert(node.getExpression()));
}
private TreeNode convertBinary(JCTree.JCBinary node) {
InfixExpression newNode = new InfixExpression();
newNode
.setTypeMirror(node.type)
.setOperator(InfixExpression.Operator.parse(node.operator.name.toString()));
// Flatten this tree to avoid stack overflow with very deep trees. This
// code traverses the subtree non-recursively and merges all children
// that have the same operator into this node.
List<StackState> stack = Lists.newArrayList();
stack.add(new StackState(node));
while (!stack.isEmpty()) {
StackState currentState = stack.get(stack.size() - 1);
JCTree.JCExpression child = currentState.nextChild();
if (child == null) {
stack.remove(stack.size() - 1);
continue;
}
if (child instanceof JCTree.JCBinary) {
JCTree.JCBinary infixChild = (JCTree.JCBinary) child;
if (infixChild.getKind() == node.getKind()) {
stack.add(new StackState(infixChild));
continue;
}
}
newNode.addOperand((Expression) convert(child));
}
return newNode;
}
private TreeNode convertBlock(JCTree.JCBlock node) {
Block newNode = new Block();
for (StatementTree stmt : node.getStatements()) {
TreeNode tree = convert(stmt);
if (tree instanceof AbstractTypeDeclaration) {
tree = new TypeDeclarationStatement().setDeclaration((AbstractTypeDeclaration) tree);
}
newNode.addStatement((Statement) tree);
}
return newNode;
}
private TreeNode convertBodyDeclaration(JCTree node, JCTree.JCModifiers modifiers,
BodyDeclaration newNode, Element element) {
return newNode
.setModifiers((int) modifiers.flags)
.setAnnotations(convertAnnotations(modifiers))
.setJavadoc((Javadoc) getAssociatedJavaDoc(node, element));
}
private TreeNode convertBooleanLiteral(JCTree.JCLiteral node) {
return new BooleanLiteral((Boolean) node.getValue(), node.type);
}
private TreeNode convertBreakStatement(JCTree.JCBreak node) {
BreakStatement newNode = new BreakStatement();
Object label = node.getLabel();
if (label != null) {
newNode.setLabel((SimpleName)
new SimpleName(label.toString()).setPosition(getPosition(node)));
}
return newNode;
}
private TreeNode convertCase(JCTree.JCCase node) {
// Case statements are converted in convertSwitch().
SwitchCase newNode = new SwitchCase();
if (node.pat != null) {
newNode.setExpression((Expression) convert(node.getExpression()));
} else {
newNode.setIsDefault(true);
}
return newNode;
}
private TreeNode convertCatch(JCTree.JCCatch node) {
return new CatchClause()
.setException((SingleVariableDeclaration) convert(node.getParameter()))
.setBody((Block) convert(node.getBlock()));
}
private TreeNode convertCharLiteral(JCTree.JCLiteral node) {
return new CharacterLiteral((Character) node.getValue(), node.type);
}
private TreeNode convertClassDeclaration(JCTree.JCClassDecl node) {
// javac defines all type declarations with JCClassDecl, so differentiate here
// to support our different declaration nodes.
if (node.sym.getKind() == ElementKind.ANNOTATION_TYPE) {
throw new AssertionError("Annotation type declaration tree conversion not implemented");
}
TypeDeclaration newNode =
(TypeDeclaration) convertAbstractTypeDeclaration(node, new TypeDeclaration());
newNode.setInterface(
node.getKind() == Kind.INTERFACE || node.getKind() == Kind.ANNOTATION_TYPE);
if (node.sym.isAnonymous()) {
newUnit.getEnv().elementUtil().mapElementType(node.sym, node.type);
}
return newNode;
}
private TreeNode convertConditionalExpression(JCTree.JCConditional node) {
return new ConditionalExpression()
.setTypeMirror(node.type)
.setExpression((Expression) convert(node.getCondition()))
.setThenExpression((Expression) convert(node.getTrueExpression()))
.setElseExpression((Expression) convert(node.getFalseExpression()));
}
private TreeNode convertContinueStatement(JCTree.JCContinue node) {
ContinueStatement newNode = new ContinueStatement();
Object label = node.getLabel();
if (label != null) {
newNode.setLabel((SimpleName)
new SimpleName(label.toString()).setPosition(getPosition(node)));
}
return newNode;
}
private TreeNode convertDoStatement(JCTree.JCDoWhileLoop node) {
return new DoStatement()
.setExpression(convertWithoutParens(node.getCondition()))
.setBody((Statement) convert(node.getStatement()));
}
private TreeNode convertEnhancedForStatement(JCTree.JCEnhancedForLoop node) {
return new EnhancedForStatement()
.setParameter((SingleVariableDeclaration) convertSingleVariable(node.getVariable())
.setPosition(getPosition(node)))
.setExpression((Expression) convert(node.getExpression()))
.setBody((Statement) convert(node.getStatement()));
}
private TreeNode convertEnum(JCTree.JCClassDecl node) {
if (node.sym.isAnonymous()) {
return convertClassDeclaration(node).setPosition(getPosition(node));
}
EnumDeclaration newNode = (EnumDeclaration) new EnumDeclaration();
convertBodyDeclaration(node, node.getModifiers(), newNode, node.sym);
newNode
.setName(convertSimpleName(node.sym, node.type, getNamePosition(node)))
.setTypeElement(node.sym);
for (JCTree bodyDecl : node.getMembers()) {
if (bodyDecl.getKind() == Kind.VARIABLE) {
TreeNode var = convertVariableDeclaration((JCTree.JCVariableDecl) bodyDecl);
if (var.getKind() == TreeNode.Kind.ENUM_CONSTANT_DECLARATION) {
newNode.addEnumConstant((EnumConstantDeclaration) var);
} else {
newNode.addBodyDeclaration((BodyDeclaration) var);
}
} else if (bodyDecl.getKind() == Kind.BLOCK) {
JCTree.JCBlock javacBlock = (JCTree.JCBlock) bodyDecl;
Block block = (Block) convert(javacBlock);
newNode.addBodyDeclaration(new Initializer(block, javacBlock.isStatic()));
} else {
newNode.addBodyDeclaration((BodyDeclaration) convert(bodyDecl));
}
}
return newNode;
}
private TreeNode copyConstantValue(JCTree node, Expression newNode) {
Object value = node.type.constValue();
if (value instanceof Integer) {
switch (node.type.baseType().getKind()) {
case BOOLEAN:
// Convert boolean values of 1/0 as true/false.
value = ((Integer) value).intValue() == 1;
break;
case CHAR:
value = (char) ((Integer) value).intValue();
break;
default: // value doesn't need to be changed.
}
}
return newNode.setConstantValue(value);
}
private TreeNode convertExpressionStatement(JCTree.JCExpressionStatement node) {
TreeNode expr = convert(node.getExpression());
if (expr instanceof Statement) {
return expr;
}
return new ExpressionStatement().setExpression((Expression) expr);
}
private TreeNode convertFieldAccess(JCTree.JCFieldAccess node) {
String fieldName = node.name.toString();
SourcePosition pos = getPosition(node);
JCTree.JCExpression selected = node.getExpression();
if (fieldName.equals("this")) {
return new ThisExpression()
.setQualifier((Name) convert(selected))
.setTypeMirror(node.sym.asType());
}
if ("super".equals(getMemberName(selected))) {
SuperFieldAccess newNode = new SuperFieldAccess()
.setVariableElement((VariableElement) node.sym)
.setTypeMirror(node.type);
if (selected.getKind() == Kind.MEMBER_SELECT) {
newNode.setQualifier((Name) convert(((JCTree.JCFieldAccess) selected).getExpression()));
}
return newNode;
}
if (node.getIdentifier().toString().equals("class")) {
return new TypeLiteral(node.type)
.setType((Type) convertType(selected.type, pos, false).setPosition(getPosition(node)));
}
if (selected.getKind() == Kind.IDENTIFIER && (!node.sym.getKind().isField()
|| ElementUtil.isConstant((VariableElement) node.sym))) {
if (selected.toString().equals("this")) {
// Just return the constant.
return new SimpleName(node.sym);
}
JCIdent ident = (JCTree.JCIdent) selected;
return new QualifiedName()
.setName(convertSimpleName(node.sym, node.type, pos))
.setQualifier(convertSimpleName(ident.sym, ident.type, pos))
.setElement(node.sym);
}
if (selected.getKind() == Kind.MEMBER_SELECT) {
TreeNode newSelected = convertFieldAccess((JCTree.JCFieldAccess) selected).setPosition(pos);
if (newSelected.getKind() == TreeNode.Kind.QUALIFIED_NAME) {
return new QualifiedName()
.setName(convertSimpleName(node.sym, node.type, pos))
.setQualifier((QualifiedName) newSelected)
.setElement(node.sym);
}
}
if (ElementUtil.isConstant((VariableElement) node.sym) && ElementUtil.isStatic(node.sym)
&& !(selected.getKind() == Kind.METHOD_INVOCATION)) {
return new QualifiedName()
.setName(convertSimpleName(node.sym, node.type, pos))
.setQualifier((Name) convert(selected))
.setElement(node.sym);
}
return new FieldAccess()
.setVariableElement((VariableElement) node.sym)
.setExpression((Expression) convert(selected))
.setName(convertSimpleName(node.sym, node.type, pos).setTypeMirror(node.type));
}
private TreeNode convertForLoop(JCTree.JCForLoop node) {
ForStatement newNode = new ForStatement()
.setExpression((Expression) convert(node.getCondition()))
.setBody((Statement) convert(node.getStatement()));
VariableDeclarationExpression lastVar = null;
for (JCTree.JCStatement initializer : node.getInitializer()) {
if (initializer.getKind() == Kind.VARIABLE) {
JCTree.JCVariableDecl var = (JCTree.JCVariableDecl) initializer;
VariableDeclarationExpression newVar = convertVariableExpression(var);
if (lastVar == null) {
newNode.addInitializer(newVar);
lastVar = newVar;
} else {
lastVar.addFragment(TreeUtil.remove(newVar.getFragment(0)));
}
} else {
assert initializer.getKind() == Kind.EXPRESSION_STATEMENT;
newNode.addInitializer((Expression)
convert(((JCTree.JCExpressionStatement) initializer).getExpression()));
}
}
for (JCTree.JCExpressionStatement updater : node.getUpdate()) {
newNode.addUpdater((Expression) convert(updater.getExpression()));
}
return newNode;
}
private TreeNode convertFunctionalExpression(JCTree.JCFunctionalExpression node,
FunctionalExpression newNode) {
for (TypeMirror type : node.targets) {
newNode.addTargetType(type);
}
return newNode.setTypeMirror(node.type);
}
private TreeNode convertIdent(JCTree.JCIdent node) {
String text = node.sym.toString();
if (text.equals("this")) {
return new ThisExpression().setTypeMirror(node.type);
}
return new SimpleName(node.sym.baseSymbol(), node.type);
}
private TreeNode convertIf(JCTree.JCIf node) {
return new IfStatement()
.setExpression(convertWithoutParens(node.getCondition()))
.setThenStatement((Statement) convert(node.getThenStatement()))
.setElseStatement((Statement) convert(node.getElseStatement()));
}
private TreeNode convertInstanceOf(JCTree.JCInstanceOf node) {
TypeMirror clazz = nameType(node.getType());
return new InstanceofExpression()
.setLeftOperand((Expression) convert(node.getExpression()))
.setRightOperand(Type.newType(clazz))
.setTypeMirror(node.type);
}
private TreeNode convertLabeledStatement(JCTree.JCLabeledStatement node) {
return new LabeledStatement()
.setLabel((SimpleName) new SimpleName(node.label.toString()).setPosition(getPosition(node)))
.setBody((Statement) convert(node.body));
}
private TreeNode convertLambda(JCTree.JCLambda node) {
LambdaExpression newNode = new LambdaExpression();
convertFunctionalExpression(node, newNode);
for (JCVariableDecl param : node.params) {
newNode.addParameter((VariableDeclaration) convert(param));
}
return newNode.setBody(convert(node.getBody()));
}
private TreeNode convertMethodReference(JCTree.JCMemberReference node, MethodReference newNode) {
convertFunctionalExpression(node, newNode);
if (node.getTypeArguments() != null) {
for (JCTree.JCExpression typeArg : node.getTypeArguments()) {
newNode.addTypeArgument(Type.newType(typeArg.type));
}
}
return newNode
.setExecutableElement((ExecutableElement) node.sym)
.setVarargsType(node.varargsElement);
}
private TreeNode convertMemberReference(JCTree.JCMemberReference node) {
Element element = node.sym;
SourcePosition pos = getPosition(node);
if (ElementUtil.isConstructor(element)) {
CreationReference newNode = new CreationReference();
convertMethodReference(node, newNode);
return newNode
.setType(Type.newType(nameType(node.expr)));
}
if (node.hasKind(JCTree.JCMemberReference.ReferenceKind.SUPER)) {
SuperMethodReference newNode = new SuperMethodReference();
convertMethodReference(node, newNode);
if (node.getQualifierExpression().getKind() == Kind.IDENTIFIER) {
// super::foo
return newNode;
} else {
// Qualifier expression is <name>."super", so it's always a JCFieldAccess.
JCTree.JCFieldAccess expr = (JCTree.JCFieldAccess) node.getQualifierExpression();
return newNode
.setQualifier(
convertSimpleName(nameSymbol(expr.selected), expr.type,
getPosition(expr.selected)));
}
}
if (node.hasKind(JCTree.JCMemberReference.ReferenceKind.UNBOUND)
|| node.hasKind(JCTree.JCMemberReference.ReferenceKind.STATIC)) {
TypeMethodReference newNode = new TypeMethodReference();
convertMethodReference(node, newNode);
return newNode
.setType(convertType(node.type, pos, false));
}
ExpressionMethodReference newNode = new ExpressionMethodReference();
convertMethodReference(node, newNode);
return newNode.setExpression((Expression) convert(node.getQualifierExpression()));
}
private TreeNode convertMethodDeclaration(JCTree.JCMethodDecl node) {
MethodDeclaration newNode = new MethodDeclaration();
convertBodyDeclaration(node, node.getModifiers(), newNode, node.sym);
for (JCTree.JCVariableDecl param : node.getParameters()) {
newNode.addParameter((SingleVariableDeclaration) convert(param));
}
return newNode
.setIsConstructor(ElementUtil.isConstructor(node.sym))
.setExecutableElement(node.sym)
.setBody((Block) convert(node.getBody()));
}
private static String getMemberName(JCTree.JCExpression node) {
switch (node.getKind()) {
case IDENTIFIER: return node.toString();
case MEMBER_SELECT: return ((JCTree.JCFieldAccess) node).name.toString();
default: return null;
}
}
private static Symbol getMemberSymbol(JCTree.JCExpression node) {
switch (node.getKind()) {
case IDENTIFIER: return ((JCTree.JCIdent) node).sym.baseSymbol();
case MEMBER_SELECT: return ((JCTree.JCFieldAccess) node).sym;
default: throw new AssertionError("Unexpected tree kind: " + node.getKind());
}
}
private TreeNode convertMethodInvocation(JCTree.JCMethodInvocation node) {
JCTree.JCExpression method = node.getMethodSelect();
String methodName = getMemberName(method);
ExecutableType type = (ExecutableType) method.type;
Symbol.MethodSymbol sym = (Symbol.MethodSymbol) getMemberSymbol(method);
JCTree.JCExpression target = method.getKind() == Kind.MEMBER_SELECT
? ((JCTree.JCFieldAccess) method).selected : null;
if ("this".equals(methodName)) {
ConstructorInvocation newNode = new ConstructorInvocation()
.setExecutablePair(new ExecutablePair(sym))
.setVarargsType(node.varargsElement);
for (JCTree.JCExpression arg : node.getArguments()) {
newNode.addArgument((Expression) convert(arg));
}
return newNode;
}
if ("super".equals(methodName)) {
SuperConstructorInvocation newNode = new SuperConstructorInvocation()
.setExecutablePair(new ExecutablePair(sym))
.setVarargsType(node.varargsElement);
if (target != null) {
newNode.setExpression((Expression) convert(target));
}
for (JCTree.JCExpression arg : node.getArguments()) {
newNode.addArgument((Expression) convert(arg));
}
return newNode;
}
if (target != null && "super".equals(getMemberName(target))) {
SuperMethodInvocation newNode = new SuperMethodInvocation()
.setExecutablePair(new ExecutablePair(sym, type))
.setVarargsType(node.varargsElement);
if (target.getKind() == Kind.MEMBER_SELECT) {
// foo.bar.MyClass.super.print(...):
// target: foo.bar.MyClass.super
// target.selected: foo.bar.MyClass
newNode.setQualifier((Name) convert(((JCTree.JCFieldAccess) target).selected));
}
for (JCTree.JCExpression arg : node.getArguments()) {
newNode.addArgument((Expression) convert(arg));
}
return newNode;
}
MethodInvocation newNode = new MethodInvocation();
if (target != null) {
newNode.setExpression((Expression) convert(target));
}
for (JCTree.JCExpression arg : node.getArguments()) {
newNode.addArgument((Expression) convert(arg));
}
return newNode
.setTypeMirror(node.type)
.setExecutablePair(new ExecutablePair(sym, type))
.setVarargsType(node.varargsElement);
}
private SimpleName convertSimpleName(Element element, TypeMirror type, SourcePosition pos) {
return (SimpleName) new SimpleName(element, type).setPosition(pos);
}
private Name convertName(Symbol symbol, SourcePosition pos) {
if (symbol.owner == null || symbol.owner.name.isEmpty()) {
return new SimpleName(symbol);
}
return new QualifiedName(symbol, symbol.asType(), convertName(symbol.owner, pos));
}
private TreeNode convertNewArray(JCTree.JCNewArray node) {
ArrayCreation newNode = new ArrayCreation();
List<Expression> dimensions = new ArrayList<>();
for (JCTree.JCExpression dimension : node.getDimensions()) {
dimensions.add((Expression) convert(dimension));
}
javax.lang.model.type.ArrayType type = (javax.lang.model.type.ArrayType) node.type;
if (node.getInitializers() != null) {
ArrayInitializer initializers = new ArrayInitializer(type);
for (JCTree.JCExpression initializer : node.getInitializers()) {
initializers.addExpression((Expression) convert(initializer));
}
newNode.setInitializer(initializers);
}
return newNode
.setType((ArrayType) new ArrayType(type).setPosition(getPosition(node)))
.setDimensions(dimensions);
}
private TreeNode convertNewClass(JCTree.JCNewClass node) {
ClassInstanceCreation newNode = new ClassInstanceCreation();
for (JCTree.JCExpression arg : node.getArguments()) {
newNode.addArgument((Expression) convert(arg));
}
return newNode
.setExecutablePair(new ExecutablePair((ExecutableElement) node.constructor))
.setVarargsType(node.varargsElement)
.setExpression((Expression) convert(node.getEnclosingExpression()))
.setType(convertType(node.clazz.type))
.setAnonymousClassDeclaration((TypeDeclaration) convert(node.def));
}
private TreeNode convertNumberLiteral(JCTree.JCLiteral node) {
return new NumberLiteral((Number) node.getValue(), node.type)
.setToken(getTreeSource(node));
}
private PackageDeclaration convertPackage(PackageElement pkg, Trees trees) {
JCTree node = (JCTree) trees.getTree(pkg);
PackageDeclaration newNode = new PackageDeclaration()
.setPackageElement(pkg);
for (JCTree.JCAnnotation pkgAnnotation : unit.getPackageAnnotations()) {
newNode.addAnnotation((Annotation) convert(pkgAnnotation));
}
if (unit.sourcefile.toUri().getPath().endsWith("package-info.java")) {
if (node == null) {
// Java 8 javac bug, fixed in Java 9. Doc-comments in package-info.java
// sources are keyed to their compilation unit, not their package node.
node = unit;
}
newNode.setJavadoc((Javadoc) getAssociatedJavaDoc(node, pkg));
}
return (PackageDeclaration) newNode.setName(convertName((PackageSymbol) pkg, getPosition(node)))
.setPosition(SourcePosition.NO_POSITION);
}
private TreeNode convertPrefixExpr(JCTree.JCUnary node) {
return new PrefixExpression()
.setTypeMirror(node.type)
.setOperator(PrefixExpression.Operator.parse(node.getOperator().name.toString()))
.setOperand((Expression) convert(node.getExpression()));
}
private TreeNode convertParens(JCTree.JCParens node) {
return new ParenthesizedExpression()
.setExpression((Expression) convert(node.getExpression()));
}
private TreeNode convertPostExpr(JCTree.JCUnary node) {
return new PostfixExpression()
.setOperator(PostfixExpression.Operator.parse(node.getOperator().name.toString()))
.setOperand((Expression) convert(node.getExpression()));
}
private TreeNode convertPrimitiveType(JCTree.JCPrimitiveTypeTree node) {
return new PrimitiveType(node.type);
}
private TreeNode convertReturn(JCTree.JCReturn node) {
return new ReturnStatement((Expression) convert(node.getExpression()));
}
private TreeNode convertStringLiteral(JCTree.JCLiteral node) {
return new StringLiteral((String) node.getValue(), node.type);
}
private TreeNode convertSwitch(JCTree.JCSwitch node) {
SwitchStatement newNode = new SwitchStatement()
.setExpression(convertWithoutParens(node.getExpression()));
for (JCTree.JCCase switchCase : node.getCases()) {
newNode.addStatement((SwitchCase) convert(switchCase));
for (JCTree.JCStatement s : switchCase.getStatements()) {
newNode.addStatement((Statement) convert(s));
}
}
return newNode;
}
private TreeNode convertSynchronized(JCTree.JCSynchronized node) {
return new SynchronizedStatement()
.setExpression((Expression) convertWithoutParens(node.getExpression())
.setPosition(getPosition(node)))
.setBody((Block) convert(node.getBlock()));
}
private TreeNode convertThrow(JCTree.JCThrow node) {
return new ThrowStatement()
.setExpression((Expression) convert(node.getExpression()));
}
private TreeNode convertTry(JCTree.JCTry node) {
TryStatement newNode = new TryStatement();
for (Object obj : node.getResources()) {
newNode.addResource(convertVariableExpression((JCTree.JCVariableDecl) obj));
}
for (Object obj : node.getCatches()) {
newNode.addCatchClause((CatchClause) convert(obj));
}
return newNode
.setBody((Block) convert(node.getBlock()))
.setFinally((Block) convert(node.getFinallyBlock()));
}
private Type convertType(TypeMirror typeMirror) {
com.sun.tools.javac.code.Type type = (com.sun.tools.javac.code.Type) typeMirror;
if (type.getKind() == TypeKind.EXECUTABLE) {
Type returnType = Type.newType(type.getReturnType());
if (type.hasTag(TypeTag.FORALL)) {
return new ParameterizedType()
.setType(returnType)
.setTypeMirror(type.getReturnType());
} else {
return returnType;
}
}
if (type.getKind() == TypeKind.DECLARED) {
List<? extends TypeMirror> typeArgs = ((DeclaredType) type).getTypeArguments();
if (!typeArgs.isEmpty()) {
return new ParameterizedType()
.setType(Type.newType(typeMirror))
.setTypeMirror(typeMirror);
}
}
return Type.newType(type);
}
private TypeMirror nameType(JCTree node) {
if (node.getKind() == Kind.PARAMETERIZED_TYPE) {
return ((JCTree.JCTypeApply) node).clazz.type;
}
if (node.getKind() == Kind.ARRAY_TYPE) {
return ((JCTree.JCArrayTypeTree) node).type;
}
return nameSymbol(node).asType();
}
private Symbol nameSymbol(JCTree node) {
return node.getKind() == Kind.MEMBER_SELECT
? ((JCTree.JCFieldAccess) node).sym
: ((JCTree.JCIdent) node).sym;
}
private TreeNode convertTypeApply(JCTree.JCTypeApply node) {
return new ParameterizedType()
.setType(Type.newType(node.type))
.setTypeMirror(node.type);
}
private TreeNode convertTypeCast(JCTree.JCTypeCast node) {
return new CastExpression(node.type, (Expression) convert(node.getExpression()));
}
private TreeNode convertVariableDeclaration(JCTree.JCVariableDecl node) {
VarSymbol var = node.sym;
if (var.getKind() == ElementKind.FIELD) {
FieldDeclaration newNode = new FieldDeclaration(var,
(Expression) convert(node.getInitializer()));
convertBodyDeclaration(node, node.getModifiers(), newNode, var);
return newNode;
}
if (var.getKind() == ElementKind.LOCAL_VARIABLE) {
return new VariableDeclarationStatement(var, (Expression) convert(node.getInitializer()));
}
if (var.getKind() == ElementKind.ENUM_CONSTANT) {
EnumConstantDeclaration newNode = new EnumConstantDeclaration()
.setVariableElement(var);
convertBodyDeclaration(node, node.getModifiers(), newNode, var);
ClassInstanceCreation init = (ClassInstanceCreation) convert(node.getInitializer());
TreeUtil.moveList(init.getArguments(), newNode.getArguments());
if (init.getAnonymousClassDeclaration() != null) {
newNode.setAnonymousClassDeclaration(TreeUtil.remove(init.getAnonymousClassDeclaration()));
}
return newNode
.setExecutablePair(init.getExecutablePair())
.setVarargsType(init.getVarargsType());
}
return convertSingleVariable(node);
}
private TreeNode convertSingleVariable(JCTree.JCVariableDecl node) {
VarSymbol var = node.sym;
SourcePosition pos = getPosition(node);
boolean isVarargs = (node.sym.flags() & Flags.VARARGS) > 0;
Type newType = convertType(var.asType(), pos, isVarargs);
return new SingleVariableDeclaration()
.setType(newType)
.setIsVarargs(isVarargs)
.setAnnotations(convertAnnotations(node.getModifiers()))
.setVariableElement(var)
.setInitializer((Expression) convert(node.getInitializer()));
}
private Type convertType(TypeMirror varType, SourcePosition pos, boolean isVarargs) {
Type newType;
if (isVarargs) {
newType = Type.newType(((javax.lang.model.type.ArrayType) varType).getComponentType());
} else {
if (varType.getKind() == TypeKind.DECLARED
&& !((DeclaredType) varType).getTypeArguments().isEmpty()) {
newType = new ParameterizedType()
.setType((SimpleType) new SimpleType(varType).setPosition(pos))
.setTypeMirror(varType);
} else if (varType.getKind() == TypeKind.UNION) {
newType = new UnionType();
newType.setTypeMirror(varType);
for (TypeMirror t : ((javax.lang.model.type.UnionType) varType).getAlternatives()) {
Type alternative = convertType(t, pos, false);
alternative.setPosition(pos);
((UnionType) newType).addType(alternative);
}
} else {
newType = Type.newType(varType);
}
}
return (Type) newType.setPosition(pos);
}
private VariableDeclarationExpression convertVariableExpression(JCTree.JCVariableDecl node) {
VarSymbol var = node.sym;
boolean isVarargs = (node.sym.flags() & Flags.VARARGS) > 0;
Type newType = convertType(var.asType(), getPosition(node), isVarargs);
VariableDeclarationFragment fragment = new VariableDeclarationFragment();
fragment
.setVariableElement(var)
.setInitializer((Expression) convert(node.getInitializer()));
return new VariableDeclarationExpression()
.setType(newType)
.addFragment(fragment);
}
private TreeNode convertWhileLoop(JCTree.JCWhileLoop node) {
return new WhileStatement()
.setExpression(convertWithoutParens(node.getCondition()))
.setBody((Statement) convert(node.getStatement()));
}
private TreeNode getAssociatedJavaDoc(JCTree node, Element element) {
Comment comment = convertAssociatedComment(node, element);
return comment != null && comment.isDocComment() ? comment : null;
}
private Comment convertAssociatedComment(JCTree node, Element element) {
boolean docCommentsEnabled = newUnit.getEnv().options().docCommentsEnabled();
DocCommentTable docComments = unit.docComments;
if (!docCommentsEnabled || docComments == null || !docComments.hasComment(node)) {
return null;
}
com.sun.tools.javac.parser.Tokens.Comment javacComment = docComments.getComment(node);
Comment comment;
switch (javacComment.getStyle()) {
case BLOCK:
comment = new BlockComment();
break;
case JAVADOC:
comment = docCommentsEnabled
? convertJavadocComment(element) : new Javadoc();
break;
case LINE:
comment = new LineComment();
break;
default:
throw new AssertionError("unknown comment type");
}
int startPos = javacComment.getSourcePos(0);
int endPos = startPos + javacComment.getText().length();
comment.setSourceRange(startPos, endPos);
comment.setLineNumber(unit.getLineMap().getLineNumber(startPos));
return comment;
}
private Javadoc convertJavadocComment(Element element) {
return JavadocConverter.convertJavadoc(element, newUnit.getSource(), env,
newUnit.getEnv().options().reportJavadocWarnings());
}
private static void addOcniComments(CompilationUnit unit, boolean jsniWarnings) {
for (OcniExtractor.OcniType kind : OcniExtractor.OcniType.values()) {
addNativeComments(unit, kind.delimiter(), "]-*/");
}
if (jsniWarnings) {
addNativeComments(unit, "/*-{", "}-*/");
}
}
private static void addNativeComments(CompilationUnit unit, String delim, String endDelim) {
// Can't use a regex because it will greedily include everything between
// the first and last closing pattern, resulting in a single comment node.
String source = unit.getSource();
int startPos = 0;
int endPos = 0;
while ((startPos = source.indexOf(delim, endPos)) > -1) {
endPos = source.indexOf(endDelim, startPos);
if (endPos > startPos) {
endPos += 4; // Include closing delimiter.
BlockComment ocniComment = new BlockComment();
ocniComment.setSourceRange(startPos, endPos - startPos);
unit.getCommentList().add(ocniComment);
}
}
}
private static String getPath(JavaFileObject file) {
String uri = file.toUri().toString();
if (uri.startsWith("mem:/")) {
// MemoryFileObject needs a custom file system for URI to return the
// correct path, so the URI string is split instead.
return uri.substring(5);
}
return file.toUri().getPath();
}
private String getTreeSource(JCTree node) {
try {
CharSequence source = unit.getSourceFile().getCharContent(true);
return source.subSequence(node.getStartPosition(), node.getEndPosition(unit.endPositions))
.toString();
} catch (IOException e) {
return node.toString();
}
}
// javac uses a JCParens for the if, do, and while statements, while JDT doesn't.
private Expression convertWithoutParens(JCTree.JCExpression condition) {
Expression result = (Expression) convert(condition);
if (result.getKind() == TreeNode.Kind.PARENTHESIZED_EXPRESSION) {
result = TreeUtil.remove(((ParenthesizedExpression) result).getExpression());
}
return result;
}
private SourcePosition getSourcePosition(int start, int end) {
if (unit.getLineMap() != null) {
int line = unit.getLineMap().getLineNumber(start);
return new SourcePosition(start, end, line);
} else {
return new SourcePosition(start, end);
}
}
// Return best guess for the position of a declaration node's name.
private SourcePosition getNamePosition(JCTree node) {
if (node.pos == -1) {
return SourcePosition.NO_POSITION;
}
String src = newUnit.getSource();
int start = node.pos;
Kind kind = node.getKind();
if (kind == Kind.ANNOTATION_TYPE || kind == Kind.CLASS
|| kind == Kind.ENUM || kind == Kind.INTERFACE) {
// Skip the class/enum/interface token.
while (src.charAt(start++) != ' ') {
}
} else if (kind != Kind.METHOD && kind != Kind.VARIABLE) {
return getPosition(node);
}
if (!Character.isJavaIdentifierStart(src.charAt(start))) {
return getPosition(node);
}
int endPos = start + 1;
while (Character.isJavaIdentifierPart(src.charAt(endPos))) {
endPos++;
}
return getSourcePosition(start, endPos);
}
// Helper class for convertBinary().
private static class StackState {
private final JCTree.JCBinary expression;
private int nextChild = -2;
private StackState(JCTree.JCBinary expr) {
expression = expr;
}
private JCTree.JCExpression nextChild() {
int childIdx = nextChild++;
if (childIdx == -2) {
return expression.getLeftOperand();
} else if (childIdx == -1) {
return expression.getRightOperand();
} else {
return null;
}
}
}
}