Java tutorial
/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html * * 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.dart.java2dart; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.dart.engine.ast.ASTNode; import com.google.dart.engine.ast.ArgumentList; import com.google.dart.engine.ast.AsExpression; import com.google.dart.engine.ast.AssignmentExpression; import com.google.dart.engine.ast.BinaryExpression; import com.google.dart.engine.ast.Block; import com.google.dart.engine.ast.BlockFunctionBody; import com.google.dart.engine.ast.BreakStatement; import com.google.dart.engine.ast.CatchClause; import com.google.dart.engine.ast.ClassDeclaration; import com.google.dart.engine.ast.ClassMember; import com.google.dart.engine.ast.Comment; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.ast.CompilationUnitMember; import com.google.dart.engine.ast.ConstructorDeclaration; import com.google.dart.engine.ast.ConstructorInitializer; import com.google.dart.engine.ast.ContinueStatement; import com.google.dart.engine.ast.Directive; import com.google.dart.engine.ast.DoubleLiteral; import com.google.dart.engine.ast.Expression; import com.google.dart.engine.ast.ExtendsClause; import com.google.dart.engine.ast.FieldDeclaration; import com.google.dart.engine.ast.FormalParameter; import com.google.dart.engine.ast.FormalParameterList; import com.google.dart.engine.ast.FunctionBody; import com.google.dart.engine.ast.Identifier; import com.google.dart.engine.ast.IfStatement; import com.google.dart.engine.ast.ImplementsClause; import com.google.dart.engine.ast.InstanceCreationExpression; import com.google.dart.engine.ast.IntegerLiteral; import com.google.dart.engine.ast.Label; import com.google.dart.engine.ast.ListLiteral; import com.google.dart.engine.ast.MethodDeclaration; import com.google.dart.engine.ast.MethodInvocation; import com.google.dart.engine.ast.NodeList; import com.google.dart.engine.ast.NullLiteral; import com.google.dart.engine.ast.PrefixedIdentifier; import com.google.dart.engine.ast.PropertyAccess; import com.google.dart.engine.ast.ReturnStatement; import com.google.dart.engine.ast.SimpleFormalParameter; import com.google.dart.engine.ast.SimpleIdentifier; import com.google.dart.engine.ast.SimpleStringLiteral; import com.google.dart.engine.ast.Statement; import com.google.dart.engine.ast.SuperConstructorInvocation; import com.google.dart.engine.ast.SuperExpression; import com.google.dart.engine.ast.TypeArgumentList; import com.google.dart.engine.ast.TypeName; import com.google.dart.engine.ast.TypeParameter; import com.google.dart.engine.ast.TypeParameterList; import com.google.dart.engine.ast.VariableDeclaration; import com.google.dart.engine.ast.VariableDeclarationList; import com.google.dart.engine.ast.WhileStatement; import com.google.dart.engine.ast.visitor.RecursiveASTVisitor; import com.google.dart.engine.scanner.Keyword; import com.google.dart.engine.scanner.StringToken; import com.google.dart.engine.scanner.Token; import com.google.dart.engine.scanner.TokenType; import com.google.dart.java2dart.util.ExecutionUtils; import com.google.dart.java2dart.util.JavaUtils; import com.google.dart.java2dart.util.RunnableEx; import static com.google.dart.java2dart.util.ASTFactory.asExpression; import static com.google.dart.java2dart.util.ASTFactory.assertStatement; import static com.google.dart.java2dart.util.ASTFactory.binaryExpression; import static com.google.dart.java2dart.util.ASTFactory.block; import static com.google.dart.java2dart.util.ASTFactory.blockFunctionBody; import static com.google.dart.java2dart.util.ASTFactory.booleanLiteral; import static com.google.dart.java2dart.util.ASTFactory.breakStatement; import static com.google.dart.java2dart.util.ASTFactory.catchClause; import static com.google.dart.java2dart.util.ASTFactory.classDeclaration; import static com.google.dart.java2dart.util.ASTFactory.compilationUnit; import static com.google.dart.java2dart.util.ASTFactory.conditionalExpression; import static com.google.dart.java2dart.util.ASTFactory.constructorDeclaration; import static com.google.dart.java2dart.util.ASTFactory.declaredIdentifier; import static com.google.dart.java2dart.util.ASTFactory.doStatement; import static com.google.dart.java2dart.util.ASTFactory.doubleLiteral; import static com.google.dart.java2dart.util.ASTFactory.emptyFunctionBody; import static com.google.dart.java2dart.util.ASTFactory.emptyStatement; import static com.google.dart.java2dart.util.ASTFactory.eolDocComment; import static com.google.dart.java2dart.util.ASTFactory.expressionFunctionBody; import static com.google.dart.java2dart.util.ASTFactory.expressionStatement; import static com.google.dart.java2dart.util.ASTFactory.extendsClause; import static com.google.dart.java2dart.util.ASTFactory.fieldDeclaration; import static com.google.dart.java2dart.util.ASTFactory.fieldFormalParameter; import static com.google.dart.java2dart.util.ASTFactory.forEachStatement; import static com.google.dart.java2dart.util.ASTFactory.forStatement; import static com.google.dart.java2dart.util.ASTFactory.formalParameterList; import static com.google.dart.java2dart.util.ASTFactory.identifier; import static com.google.dart.java2dart.util.ASTFactory.ifStatement; import static com.google.dart.java2dart.util.ASTFactory.implementsClause; import static com.google.dart.java2dart.util.ASTFactory.indexExpression; import static com.google.dart.java2dart.util.ASTFactory.instanceCreationExpression; import static com.google.dart.java2dart.util.ASTFactory.integer; import static com.google.dart.java2dart.util.ASTFactory.integerHex; import static com.google.dart.java2dart.util.ASTFactory.isExpression; import static com.google.dart.java2dart.util.ASTFactory.label; import static com.google.dart.java2dart.util.ASTFactory.labeledStatement; import static com.google.dart.java2dart.util.ASTFactory.listLiteral; import static com.google.dart.java2dart.util.ASTFactory.listType; import static com.google.dart.java2dart.util.ASTFactory.methodDeclaration; import static com.google.dart.java2dart.util.ASTFactory.methodInvocation; import static com.google.dart.java2dart.util.ASTFactory.nullLiteral; import static com.google.dart.java2dart.util.ASTFactory.parenthesizedExpression; import static com.google.dart.java2dart.util.ASTFactory.postfixExpression; import static com.google.dart.java2dart.util.ASTFactory.prefixExpression; import static com.google.dart.java2dart.util.ASTFactory.propertyAccess; import static com.google.dart.java2dart.util.ASTFactory.simpleFormalParameter; import static com.google.dart.java2dart.util.ASTFactory.string; import static com.google.dart.java2dart.util.ASTFactory.superConstructorInvocation; import static com.google.dart.java2dart.util.ASTFactory.thisExpression; import static com.google.dart.java2dart.util.ASTFactory.throwExpression; import static com.google.dart.java2dart.util.ASTFactory.tryStatement; import static com.google.dart.java2dart.util.ASTFactory.typeName; import static com.google.dart.java2dart.util.ASTFactory.typeParameter; import static com.google.dart.java2dart.util.ASTFactory.typeParameterList; import static com.google.dart.java2dart.util.ASTFactory.variableDeclaration; import static com.google.dart.java2dart.util.ASTFactory.variableDeclarationList; import static com.google.dart.java2dart.util.ASTFactory.variableDeclarationStatement; import static com.google.dart.java2dart.util.ASTFactory.whileStatement; import static com.google.dart.java2dart.util.TokenFactory.token; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.core.runtime.Assert; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; import org.eclipse.jdt.core.dom.ConstructorInvocation; import org.eclipse.jdt.core.dom.EnumDeclaration; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.Type; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigInteger; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** * Translates Java AST to Dart AST. */ public class SyntaxTranslator extends org.eclipse.jdt.core.dom.ASTVisitor { public static final String ENUM_NAME_FIELD_NAME = "name"; public static final String ENUM_ORDINAL_FIELD_NAME = "ordinal"; private static final String ENUM_NAME_FIELD_COMMENT = "/// The name of this enum constant, as declared in the enum declaration."; private static final String ENUM_ORDINAL_FIELD_COMMENT = "/// The position in the enum declaration."; /** * Replaces "node" with "replacement" in parent of "node". */ public static void replaceNode(ASTNode parent, ASTNode node, ASTNode replacement) { Class<? extends ASTNode> parentClass = parent.getClass(); // try get/set methods try { for (Method getMethod : parentClass.getMethods()) { String getName = getMethod.getName(); if (getName.startsWith("get") && getMethod.getParameterTypes().length == 0 && getMethod.invoke(parent) == node) { String setName = "set" + getName.substring(3); Method setMethod = parentClass.getMethod(setName, getMethod.getReturnType()); setMethod.invoke(parent, replacement); return; } } } catch (Throwable e) { ExecutionUtils.propagate(e); } // special cases if (parent instanceof ListLiteral) { List<Expression> elements = ((ListLiteral) parent).getElements(); int index = elements.indexOf(node); if (index != -1) { elements.set(index, (Expression) replacement); return; } } if (parent instanceof ArgumentList) { List<Expression> arguments = ((ArgumentList) parent).getArguments(); int index = arguments.indexOf(node); if (index != -1) { arguments.set(index, (Expression) replacement); return; } } if (parent instanceof TypeArgumentList) { List<TypeName> arguments = ((TypeArgumentList) parent).getArguments(); int index = arguments.indexOf(node); if (index != -1) { arguments.set(index, (TypeName) replacement); return; } } // not found throw new UnsupportedOperationException("" + parentClass); } /** * Translates given Java AST into Dart AST. */ public static CompilationUnit translate(Context context, org.eclipse.jdt.core.dom.CompilationUnit javaUnit) { SyntaxTranslator translator = new SyntaxTranslator(context); javaUnit.accept(translator); return (CompilationUnit) translator.result; } static Expression getPrimitiveTypeDefaultValue(String typeName) { if ("bool".equals(typeName)) { return booleanLiteral(false); } if ("int".equals(typeName)) { return integer(0); } if ("double".equals(typeName)) { return doubleLiteral(0.0); } return null; } //TODO(scheglov) improve JavaDoc translation // /** // * Escapes characters in the JavaDoc to make it valid DartDoc. // */ // private static String escapeDartDoc(String javaTagString) { // // remove (and remember) leading spaces and "*" // String leadingSpaces = StringUtils.substringBefore(javaTagString, "*"); // javaTagString = javaTagString.substring(leadingSpaces.length() + 1); // // translate characters, do escaping // StringBuilder sb = new StringBuilder(); // int length = javaTagString.length(); // for (int i = 0; i < length; i++) { // char c = javaTagString.charAt(i); // // don't escape * if there are spaces befor and after it // if (c == '*' && i > 0 && javaTagString.charAt(i - 1) == ' ' && i < length - 1 // && javaTagString.charAt(i + 1) == ' ') { // sb.append(c); // continue; // } // // Complete set: "\\`*_{}[]()#+-.!" // if ("\\`*_{}[]()#+-!".indexOf(c) != -1) { // sb.append('\\'); // } // sb.append(c); // } // // return with spaces and "*" // return leadingSpaces + "*" + sb.toString(); // } private static org.eclipse.jdt.core.dom.MethodDeclaration getEnclosingMethod( org.eclipse.jdt.core.dom.ASTNode node) { while (node != null) { if (node instanceof org.eclipse.jdt.core.dom.MethodDeclaration) { return (org.eclipse.jdt.core.dom.MethodDeclaration) node; } node = node.getParent(); } return null; } private static org.eclipse.jdt.core.dom.ITypeBinding getEnclosingTypeBinding( org.eclipse.jdt.core.dom.ASTNode node) { while (node != null) { if (node instanceof org.eclipse.jdt.core.dom.TypeDeclaration) { return ((org.eclipse.jdt.core.dom.TypeDeclaration) node).resolveBinding(); } if (node instanceof org.eclipse.jdt.core.dom.AnonymousClassDeclaration) { return ((org.eclipse.jdt.core.dom.AnonymousClassDeclaration) node).resolveBinding(); } if (node instanceof org.eclipse.jdt.core.dom.EnumDeclaration) { return ((org.eclipse.jdt.core.dom.EnumDeclaration) node).resolveBinding(); } node = node.getParent(); } return null; } /** * @return the {@link Method} of {@link SyntaxTranslator} to translate * {@link org.eclipse.jdt.core.dom.ASTNode} of the given class. */ private static Method getMostSpecificMethod(Class<?> argumentType) throws Exception { Method resultMethod = null; for (Method method : SyntaxTranslator.class.getMethods()) { if (method.getName().equals("visit")) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1 && parameterTypes[0] == argumentType) { resultMethod = method; break; } } } Assert.isNotNull(resultMethod); return resultMethod; } private static boolean hasConstructorInvocation(org.eclipse.jdt.core.dom.ASTNode node) { final AtomicBoolean result = new AtomicBoolean(); node.accept(new ASTVisitor() { @Override public boolean visit(ConstructorInvocation node) { result.set(true); return false; } }); return result.get(); } private static boolean isInEnumConstructor(org.eclipse.jdt.core.dom.ASTNode node) { boolean inConstructor = false; while (node != null) { if (node instanceof org.eclipse.jdt.core.dom.MethodDeclaration) { inConstructor = ((org.eclipse.jdt.core.dom.MethodDeclaration) node).isConstructor(); } if (node instanceof org.eclipse.jdt.core.dom.EnumDeclaration) { return inConstructor; } node = node.getParent(); } return false; } private static boolean isIntegerType(org.eclipse.jdt.core.dom.Expression expression) { ITypeBinding typeBinding = expression.resolveTypeBinding(); return JavaUtils.isTypeNamed(typeBinding, "int") || JavaUtils.isTypeNamed(typeBinding, "long") || JavaUtils.isTypeNamed(typeBinding, "short"); } /** * @return <code>true</code> if "subConstructor" is constructor of inner class which call * "superConstructor". */ private static boolean isSuperConstructor(IMethodBinding superConstructor, IMethodBinding subConstructor) { String superString = superConstructor.toString(); String subString = subConstructor.toString(); return superString.endsWith(subString); } private static int numberOfConstructors(org.eclipse.jdt.core.dom.ASTNode node) { int count = 0; if (node instanceof org.eclipse.jdt.core.dom.TypeDeclaration) { org.eclipse.jdt.core.dom.TypeDeclaration typeDecl = (org.eclipse.jdt.core.dom.TypeDeclaration) node; for (org.eclipse.jdt.core.dom.MethodDeclaration methodDecl : typeDecl.getMethods()) { if (methodDecl.isConstructor()) { count++; } } return count; } if (node instanceof EnumDeclaration) { EnumDeclaration enumDecl = (EnumDeclaration) node; for (Object child : (List<?>) enumDecl.bodyDeclarations()) { if (child instanceof org.eclipse.jdt.core.dom.MethodDeclaration) { org.eclipse.jdt.core.dom.MethodDeclaration methodDecl = (org.eclipse.jdt.core.dom.MethodDeclaration) child; if (methodDecl.isConstructor()) { count++; } } } return count; } throw new UnsupportedOperationException("not implemented: " + node.getClass()); } private final Context context; private ASTNode result; private final List<CompilationUnitMember> artificialUnitDeclarations = Lists.newArrayList(); private MethodDeclaration constructorImpl; private SyntaxTranslator(Context context) { this.context = context; } @Override public boolean visit(org.eclipse.jdt.core.dom.ArrayAccess node) { Expression expression = translate(node.getArray()); Expression index = translate(node.getIndex()); return done(indexExpression(expression, index)); } @Override public boolean visit(org.eclipse.jdt.core.dom.ArrayCreation node) { TypeName listType = translate(node.getType()); TypeArgumentList typeArgs = listType.getTypeArguments(); if (node.getInitializer() != null) { List<Expression> elements = translateExpressionList(node.getInitializer().expressions()); return done(listLiteral(null, typeArgs, elements)); } else { List<Expression> arguments = translateArguments(null, node.dimensions()); // may be primitive array element { String arrayElementTypeName = typeArgs.getArguments().get(0).getName().getName(); Expression initializer = getPrimitiveTypeDefaultValue(arrayElementTypeName); if (initializer != null) { arguments.add(initializer); return done(instanceCreationExpression(Keyword.NEW, listType, "filled", arguments)); } } // non-primitive array element return done(instanceCreationExpression(Keyword.NEW, listType, arguments)); } } @Override public boolean visit(org.eclipse.jdt.core.dom.ArrayInitializer node) { List<Expression> elements = translateExpressionList(node.expressions()); return done(listLiteral(elements)); } @Override public boolean visit(org.eclipse.jdt.core.dom.ArrayType node) { TypeName elementType = translate(node.getElementType()); int dimensions = node.getDimensions(); return done(listType(elementType, dimensions)); } @Override public boolean visit(org.eclipse.jdt.core.dom.AssertStatement node) { return done(assertStatement(translateExpression(node.getExpression()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.Assignment node) { Expression left = translate(node.getLeftHandSide()); Expression right = translate(node.getRightHandSide()); // operator TokenType tokenType = null; org.eclipse.jdt.core.dom.Assignment.Operator javaOperator = node.getOperator(); if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.ASSIGN) { tokenType = TokenType.EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.PLUS_ASSIGN) { tokenType = TokenType.PLUS_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.MINUS_ASSIGN) { tokenType = TokenType.MINUS_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.TIMES_ASSIGN) { tokenType = TokenType.STAR_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.DIVIDE_ASSIGN) { tokenType = TokenType.SLASH_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.REMAINDER_ASSIGN) { tokenType = TokenType.PERCENT_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.LEFT_SHIFT_ASSIGN) { tokenType = TokenType.LT_LT_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.RIGHT_SHIFT_SIGNED_ASSIGN || javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.RIGHT_SHIFT_UNSIGNED_ASSIGN) { tokenType = TokenType.GT_GT_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.BIT_XOR_ASSIGN) { tokenType = TokenType.CARET_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.BIT_OR_ASSIGN) { tokenType = TokenType.BAR_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.Assignment.Operator.BIT_AND_ASSIGN) { tokenType = TokenType.AMPERSAND_EQ; } Assert.isNotNull(tokenType, "No token for: " + javaOperator); // done return done(new AssignmentExpression(left, new Token(tokenType, 0), right)); } @Override public boolean visit(org.eclipse.jdt.core.dom.Block node) { List<Statement> statements = Lists.newArrayList(); for (Iterator<?> I = node.statements().iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.Statement javaStatement = (org.eclipse.jdt.core.dom.Statement) I.next(); if (javaStatement instanceof org.eclipse.jdt.core.dom.SuperConstructorInvocation) { continue; } statements.add((Statement) translate(javaStatement)); } return done(block(statements)); } @Override public boolean visit(org.eclipse.jdt.core.dom.BooleanLiteral node) { boolean value = node.booleanValue(); return done(booleanLiteral(value)); } @Override public boolean visit(org.eclipse.jdt.core.dom.BreakStatement node) { SimpleIdentifier label = translate(node.getLabel()); return done(breakStatement(label)); } @Override public boolean visit(org.eclipse.jdt.core.dom.CastExpression node) { Expression expression = translate(node.getExpression()); TypeName typeName = translate(node.getType()); AsExpression asExpression = asExpression(expression, typeName); return done(parenthesizedExpression(asExpression)); } @Override public boolean visit(org.eclipse.jdt.core.dom.CatchClause node) { SimpleIdentifier exceptionParameter = translateSimpleName(node.getException().getName()); Block block = translate(node.getBody()); // "catch (e) {}" or "on Type catch (e) {}" Type javaExceptionType = node.getException().getType(); ITypeBinding javaExceptionBinding = javaExceptionType.resolveBinding(); if (JavaUtils.isTypeNamed(javaExceptionBinding, "java.lang.Exception")) { return done(catchClause(null, exceptionParameter, null, block)); } else { TypeName exceptionType = translate(javaExceptionType); return done(catchClause(exceptionType, exceptionParameter, null, block)); } } @Override public boolean visit(org.eclipse.jdt.core.dom.CharacterLiteral node) { int intValue = node.charValue(); return done(integerHex(intValue)); } @Override public boolean visit(org.eclipse.jdt.core.dom.ClassInstanceCreation node) { IMethodBinding binding = node.resolveConstructorBinding(); String signature = JavaUtils.getJdtSignature(binding); TypeName typeNameNode = (TypeName) translate(node.getType()); final List<Expression> arguments = translateArguments(binding, node.arguments()); final ClassDeclaration innerClass; { AnonymousClassDeclaration anoDeclaration = node.getAnonymousClassDeclaration(); if (anoDeclaration != null) { ITypeBinding superclass = anoDeclaration.resolveBinding().getSuperclass(); signature = superclass.getKey() + StringUtils.substringAfter(signature, ";"); String name = typeNameNode.getName().getName().replace('.', '_'); name = name + "_" + context.generateTechnicalAnonymousClassIndex(); innerClass = declareInnerClass(binding, anoDeclaration, name, ArrayUtils.EMPTY_STRING_ARRAY); typeNameNode = typeName(name); // prepare enclosing type final ITypeBinding enclosingTypeBinding = getEnclosingTypeBinding(node); final SimpleIdentifier enclosingTypeRef; final AtomicBoolean addEnclosingTypeRef = new AtomicBoolean(); { if (enclosingTypeBinding != null) { enclosingTypeRef = identifier(enclosingTypeBinding.getName() + "_this"); // add enclosing class references innerClass.accept(new RecursiveASTVisitor<Void>() { @Override public Void visitMethodInvocation(MethodInvocation node) { if (node.getTarget() == null) { IMethodBinding methodBinding = (IMethodBinding) context.getNodeBinding(node); if (methodBinding != null && methodBinding.getDeclaringClass() == enclosingTypeBinding) { addEnclosingTypeRef.set(true); node.setTarget(enclosingTypeRef); } } return super.visitMethodInvocation(node); } @Override public Void visitSimpleIdentifier(SimpleIdentifier node) { if (!(node.getParent() instanceof PropertyAccess) && !(node.getParent() instanceof PrefixedIdentifier)) { Object binding = context.getNodeBinding(node); if (binding instanceof IVariableBinding) { IVariableBinding variableBinding = (IVariableBinding) binding; if (variableBinding.isField() && variableBinding.getDeclaringClass() == enclosingTypeBinding) { addEnclosingTypeRef.set(true); replaceNode(node.getParent(), node, propertyAccess(enclosingTypeRef, node)); } } } return super.visitSimpleIdentifier(node); } }); } else { enclosingTypeRef = null; } } // declare referenced final variables XXX final String finalName = name; anoDeclaration.accept(new ASTVisitor() { final Set<org.eclipse.jdt.core.dom.IVariableBinding> addedParameters = Sets.newHashSet(); final List<FormalParameter> constructorParameters = Lists.newArrayList(); int index; @Override public void endVisit(AnonymousClassDeclaration node) { if (!constructorParameters.isEmpty()) { // add parameters to the existing "inner" constructor XXX for (ClassMember classMember : innerClass.getMembers()) { if (classMember instanceof ConstructorDeclaration) { ConstructorDeclaration innerConstructor = (ConstructorDeclaration) classMember; innerConstructor.getParameters().getParameters().addAll(constructorParameters); return; } } // create new "inner" constructor innerClass.getMembers().add(index, constructorDeclaration(identifier(finalName), null, formalParameterList(constructorParameters), null)); } super.endVisit(node); } @Override public void endVisit(SimpleName node) { IBinding nameBinding = node.resolveBinding(); if (nameBinding instanceof org.eclipse.jdt.core.dom.IVariableBinding) { org.eclipse.jdt.core.dom.IVariableBinding variableBinding = (org.eclipse.jdt.core.dom.IVariableBinding) nameBinding; org.eclipse.jdt.core.dom.MethodDeclaration enclosingMethod = getEnclosingMethod(node); if (!variableBinding.isField() && enclosingMethod != null && variableBinding.getDeclaringMethod() != enclosingMethod.resolveBinding() && addedParameters.add(variableBinding)) { TypeName parameterTypeName = translateTypeName(variableBinding.getType()); String parameterName = variableBinding.getName(); SimpleIdentifier parameterNameNode = identifier(parameterName); innerClass.getMembers().add(index++, fieldDeclaration(parameterTypeName, variableDeclaration(parameterNameNode))); constructorParameters.add(fieldFormalParameter(null, null, parameterNameNode)); arguments.add(parameterNameNode); context.putReference(parameterNameNode, variableBinding, null); } } super.endVisit(node); } @Override public boolean visit(AnonymousClassDeclaration node) { if (addEnclosingTypeRef.get()) { TypeName parameterTypeName = translateTypeName(enclosingTypeBinding); innerClass.getMembers().add(index++, fieldDeclaration(false, Keyword.FINAL, parameterTypeName, variableDeclaration(enclosingTypeRef))); constructorParameters.add(fieldFormalParameter(null, null, enclosingTypeRef)); arguments.add(thisExpression()); } return super.visit(node); } }); } else { innerClass = null; } } InstanceCreationExpression creation = instanceCreationExpression(Keyword.NEW, typeNameNode, null, arguments); context.putNodeBinding(creation, binding); context.putAnonymousDeclaration(creation, innerClass); context.getConstructorDescription(binding).instanceCreations.add(creation); return done(creation); } @Override public boolean visit(org.eclipse.jdt.core.dom.CompilationUnit node) { List<Directive> directives = Lists.newArrayList(); List<CompilationUnitMember> declarations = Lists.newArrayList(); for (Iterator<?> I = node.types().iterator(); I.hasNext();) { Object javaType = I.next(); ClassDeclaration dartClass = translate((org.eclipse.jdt.core.dom.ASTNode) javaType); declarations.add(dartClass); declarations.addAll(artificialUnitDeclarations); artificialUnitDeclarations.clear(); } return done(compilationUnit(directives, declarations)); } @Override public boolean visit(org.eclipse.jdt.core.dom.ConditionalExpression node) { return done(conditionalExpression(translateExpression(node.getExpression()), translateExpression(node.getThenExpression()), translateExpression(node.getElseExpression()))); } /** * We generate invocation of "impl" method instead of redirecting constructor invocation. The * reason is that in Java it is possible to have "redirecting constructor invocation" as first * statement of constructor and then any other statement. But in Dart redirection should be only * clause. */ @Override public boolean visit(org.eclipse.jdt.core.dom.ConstructorInvocation node) { IMethodBinding binding = node.resolveConstructorBinding(); SimpleIdentifier nameNode = identifier("jtdTmp"); context.getConstructorDescription(binding).implInvocations.add(nameNode); // invoke "impl" List<Expression> arguments = translateArguments(binding, node.arguments()); MethodInvocation invocation = methodInvocation(nameNode, arguments); context.putNodeBinding(invocation, binding); return done(expressionStatement(invocation)); } @Override public boolean visit(org.eclipse.jdt.core.dom.ContinueStatement node) { return done(new ContinueStatement(null, (SimpleIdentifier) translate(node.getLabel()), null)); } @Override public boolean visit(org.eclipse.jdt.core.dom.DoStatement node) { return done(doStatement((Statement) translate(node.getBody()), translateExpression(node.getExpression()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.EmptyStatement node) { return done(emptyStatement()); } @Override public boolean visit(org.eclipse.jdt.core.dom.EnhancedForStatement node) { SimpleFormalParameter sfp = (SimpleFormalParameter) translate(node.getParameter()); return done(forEachStatement(declaredIdentifier(sfp.getType(), sfp.getIdentifier()), translateExpression(node.getExpression()), (Statement) translate(node.getBody()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.EnumConstantDeclaration node) { String fieldName = node.getName().getIdentifier(); IMethodBinding constructorBinding = node.resolveConstructorBinding(); // prepare enum name org.eclipse.jdt.core.dom.EnumDeclaration parentEnum = (org.eclipse.jdt.core.dom.EnumDeclaration) node .getParent(); String enumTypeName = parentEnum.getName().getIdentifier(); // may be create Dart top-level class for Java inner class String innerClassName = null; { AnonymousClassDeclaration anoClassDeclaration = node.getAnonymousClassDeclaration(); if (anoClassDeclaration != null) { innerClassName = enumTypeName + "_" + fieldName; declareInnerClass(constructorBinding, anoClassDeclaration, innerClassName, new String[] { "String", ENUM_NAME_FIELD_NAME, "int", ENUM_ORDINAL_FIELD_NAME }); } } // prepare field type TypeName type = typeName(enumTypeName); // prepare field variables List<VariableDeclaration> variables = Lists.newArrayList(); { List<Expression> argList = translateArguments(null, node.arguments()); { int ordinal = parentEnum.enumConstants().indexOf(node); argList.add(0, integer(ordinal)); argList.add(0, string(fieldName)); } InstanceCreationExpression init; if (innerClassName == null) { init = instanceCreationExpression(Keyword.NEW, typeName(enumTypeName), argList); context.getConstructorDescription(constructorBinding).instanceCreations.add(init); } else { init = instanceCreationExpression(Keyword.NEW, typeName(innerClassName), argList); } variables.add(variableDeclaration(fieldName, init)); } return done(fieldDeclaration(translateJavadoc(node), true, Keyword.FINAL, type, variables)); } @Override @SuppressWarnings("unchecked") public boolean visit(org.eclipse.jdt.core.dom.EnumDeclaration node) { SimpleIdentifier name = translateSimpleName(node.getName()); // implements ImplementsClause implementsClause; { List<TypeName> interfaces = Lists.newArrayList(); // add Comparable interfaces.add(typeName("Comparable", typeName(name))); // add declared interfaces if (!node.superInterfaceTypes().isEmpty()) { for (Object javaInterface : node.superInterfaceTypes()) { interfaces.add((TypeName) translate((org.eclipse.jdt.core.dom.ASTNode) javaInterface)); } } // create ImplementsClause implementsClause = new ImplementsClause(null, interfaces); } // members List<ClassMember> members = Lists.newArrayList(); { // constants List<Expression> valuesList = Lists.newArrayList(); for (Object javaConst : node.enumConstants()) { org.eclipse.jdt.core.dom.EnumConstantDeclaration javaEnumConst = (org.eclipse.jdt.core.dom.EnumConstantDeclaration) javaConst; members.add((FieldDeclaration) translate(javaEnumConst)); valuesList.add(identifier(javaEnumConst.getName().getIdentifier())); } // values members.add(fieldDeclaration(true, Keyword.FINAL, listType(typeName(name), 1), variableDeclaration("values", listLiteral(valuesList)))); // body declarations members.add(fieldDeclaration(eolDocComment(ENUM_NAME_FIELD_COMMENT), false, Keyword.FINAL, typeName("String"), variableDeclaration(ENUM_NAME_FIELD_NAME))); members.add(fieldDeclaration(eolDocComment(ENUM_ORDINAL_FIELD_COMMENT), false, Keyword.FINAL, typeName("int"), variableDeclaration(ENUM_ORDINAL_FIELD_NAME))); boolean hasConstructor = false; for (Iterator<?> I = node.bodyDeclarations().iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.BodyDeclaration javaBodyDecl = (org.eclipse.jdt.core.dom.BodyDeclaration) I .next(); constructorImpl = null; ClassMember member = translate(javaBodyDecl); members.add(member); if (constructorImpl != null) { members.add(constructorImpl); } if (javaBodyDecl instanceof org.eclipse.jdt.core.dom.MethodDeclaration) { if (((org.eclipse.jdt.core.dom.MethodDeclaration) javaBodyDecl).isConstructor()) { hasConstructor = true; } } } // add default constructor, use artificial constructor if (!hasConstructor) { org.eclipse.jdt.core.dom.MethodDeclaration ac = node.getAST().newMethodDeclaration(); try { ac.setConstructor(true); ac.setName(node.getAST().newSimpleName(name.getName())); ac.setBody(node.getAST().newBlock()); node.bodyDeclarations().add(ac); ConstructorDeclaration innerConstructor = translate(ac); members.add(innerConstructor); if (constructorImpl != null) { members.add(constructorImpl); } } finally { node.bodyDeclarations().remove(ac); } } // compareTo() members.add(methodDeclaration(typeName("int"), identifier("compareTo"), formalParameterList(simpleFormalParameter(typeName(name), "other")), expressionFunctionBody(binaryExpression(identifier(ENUM_ORDINAL_FIELD_NAME), TokenType.MINUS, propertyAccess(identifier("other"), identifier(ENUM_ORDINAL_FIELD_NAME)))))); // toString() members.add(methodDeclaration(typeName("String"), identifier("toString"), formalParameterList(), expressionFunctionBody(identifier(ENUM_NAME_FIELD_NAME)))); } return done(classDeclaration(translateJavadoc(node), name, null, null, implementsClause, members)); } @Override public boolean visit(org.eclipse.jdt.core.dom.ExpressionStatement node) { Expression expression = translate(node.getExpression()); return done(expressionStatement(expression)); } @Override public boolean visit(org.eclipse.jdt.core.dom.FieldAccess node) { PropertyAccess result = propertyAccess(translateExpression(node.getExpression()), (SimpleIdentifier) translate(node.getName())); context.putNodeBinding(result, node.resolveFieldBinding()); return done(result); } @Override public boolean visit(org.eclipse.jdt.core.dom.FieldDeclaration node) { boolean isNotPublic = !org.eclipse.jdt.core.dom.Modifier.isPublic(node.getModifiers()); boolean isStatic = org.eclipse.jdt.core.dom.Modifier.isStatic(node.getModifiers()); FieldDeclaration fieldDeclaration = fieldDeclaration(translateJavadoc(node), isStatic, translateVariableDeclarationList(false, node.getType(), node.fragments())); if (isNotPublic) { context.putPrivateClassMember(fieldDeclaration); } return done(fieldDeclaration); } @Override public boolean visit(org.eclipse.jdt.core.dom.ForStatement node) { Expression condition = translateExpression(node.getExpression()); List<Expression> updaters = translateExpressionList(node.updaters()); Statement body = (Statement) translate(node.getBody()); Object javaInitializer = !node.initializers().isEmpty() ? node.initializers().get(0) : null; if (javaInitializer instanceof org.eclipse.jdt.core.dom.VariableDeclarationExpression) { org.eclipse.jdt.core.dom.VariableDeclarationExpression javaVDE = (org.eclipse.jdt.core.dom.VariableDeclarationExpression) javaInitializer; List<VariableDeclaration> variables = Lists.newArrayList(); for (Iterator<?> I = javaVDE.fragments().iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.VariableDeclarationFragment fragment = (org.eclipse.jdt.core.dom.VariableDeclarationFragment) I .next(); variables.add((VariableDeclaration) translate(fragment)); } VariableDeclarationList variableList = variableDeclarationList(null, (TypeName) translate(javaVDE.getType()), variables); return done(forStatement(variableList, condition, updaters, body)); } else { Expression initializer = translate((org.eclipse.jdt.core.dom.ASTNode) javaInitializer); return done(forStatement(initializer, condition, updaters, body)); } } @Override public boolean visit(org.eclipse.jdt.core.dom.IfStatement node) { return done(ifStatement(translateExpression(node.getExpression()), (Statement) translate(node.getThenStatement()), (Statement) translate(node.getElseStatement()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.InfixExpression node) { Expression left = translate(node.getLeftOperand()); Expression right = translate(node.getRightOperand()); // operator TokenType tokenType = null; org.eclipse.jdt.core.dom.InfixExpression.Operator javaOperator = node.getOperator(); if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.PLUS) { tokenType = TokenType.PLUS; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.MINUS) { tokenType = TokenType.MINUS; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.TIMES) { tokenType = TokenType.STAR; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.DIVIDE) { if (isIntegerType(node.getLeftOperand()) && isIntegerType(node.getRightOperand())) { tokenType = TokenType.TILDE_SLASH; } else { tokenType = TokenType.SLASH; } } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.REMAINDER) { tokenType = TokenType.PERCENT; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.LEFT_SHIFT) { tokenType = TokenType.LT_LT; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.RIGHT_SHIFT_SIGNED || javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED) { tokenType = TokenType.GT_GT; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.CONDITIONAL_OR) { tokenType = TokenType.BAR_BAR; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.CONDITIONAL_AND) { tokenType = TokenType.AMPERSAND_AMPERSAND; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.XOR) { tokenType = TokenType.CARET; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.OR) { tokenType = TokenType.BAR; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.AND) { tokenType = TokenType.AMPERSAND; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.LESS) { tokenType = TokenType.LT; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.GREATER) { tokenType = TokenType.GT; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.LESS_EQUALS) { tokenType = TokenType.LT_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.GREATER_EQUALS) { tokenType = TokenType.GT_EQ; } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.EQUALS) { if (isNumberOrNull(left) || isNumberOrNull(right)) { tokenType = TokenType.EQ_EQ; } else { return done(methodInvocation("identical", left, right)); } } if (javaOperator == org.eclipse.jdt.core.dom.InfixExpression.Operator.NOT_EQUALS) { tokenType = TokenType.BANG_EQ; } Assert.isNotNull(tokenType, "No token for: " + javaOperator); // create BinaryExpression BinaryExpression binary = binaryExpression(left, tokenType, right); for (Object javaOperand : node.extendedOperands()) { Expression operand = translate((org.eclipse.jdt.core.dom.ASTNode) javaOperand); binary = binaryExpression(binary, tokenType, operand); } return done(binary); } @Override public boolean visit(org.eclipse.jdt.core.dom.InstanceofExpression node) { return done(isExpression(translateExpression(node.getLeftOperand()), false, (TypeName) translate(node.getRightOperand()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.Javadoc node) { StringBuilder buffer = new StringBuilder(); { buffer.append("/**"); for (Object javaTag : node.tags()) { String javaTagString = javaTag.toString(); String dartDocString = StringUtils.replace(javaTagString, "[", "\\["); ; dartDocString = StringUtils.replace(dartDocString, "]", "\\]"); ; // TODO(scheglov) improve JavaDoc translation // String dartDocString = escapeDartDoc(javaTagString); buffer.append(dartDocString); } buffer.append("\n */\n"); } StringToken commentToken = new StringToken(TokenType.STRING, buffer.toString(), 0); return done(Comment.createDocumentationComment(new Token[] { commentToken })); } @Override public boolean visit(org.eclipse.jdt.core.dom.LabeledStatement node) { List<Label> labels = Lists.newArrayList(); while (true) { SimpleIdentifier labelIdentifier = translate(node.getLabel()); labels.add(label(labelIdentifier)); if (node.getBody() instanceof org.eclipse.jdt.core.dom.LabeledStatement) { node = (org.eclipse.jdt.core.dom.LabeledStatement) node.getBody(); } else { break; } } return done(labeledStatement(labels, (Statement) translate(node.getBody()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.MethodDeclaration node) { boolean isNotPublic = !org.eclipse.jdt.core.dom.Modifier.isPublic(node.getModifiers()); IMethodBinding binding = node.resolveBinding(); boolean isEnumConstructor = node.isConstructor() && node.getParent() instanceof org.eclipse.jdt.core.dom.EnumDeclaration; // parameters FormalParameterList parameterList; { List<FormalParameter> parameters = Lists.newArrayList(); for (Iterator<?> I = node.parameters().iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.SingleVariableDeclaration javaParameter = (org.eclipse.jdt.core.dom.SingleVariableDeclaration) I .next(); SimpleFormalParameter parameter = translate(javaParameter); parameters.add(parameter); } parameterList = formalParameterList(parameters); } // body FunctionBody body; SuperConstructorInvocation superConstructorInvocation = null; { org.eclipse.jdt.core.dom.Block javaBlock = node.getBody(); if (javaBlock != null) { for (Object javaStatement : javaBlock.statements()) { if (javaStatement instanceof org.eclipse.jdt.core.dom.SuperConstructorInvocation) { superConstructorInvocation = translate( (org.eclipse.jdt.core.dom.SuperConstructorInvocation) javaStatement); } } Block bodyBlock = (Block) translate(javaBlock); body = new BlockFunctionBody(bodyBlock); NodeList<Statement> statements = bodyBlock.getStatements(); // convert "{ return foo; }" to "=> foo;" if (statements.size() == 1 && statements.get(0) instanceof ReturnStatement) { body = expressionFunctionBody(((ReturnStatement) statements.get(0)).getExpression()); } } else { body = emptyFunctionBody(); } } // constructor if (node.isConstructor()) { boolean multipleConstructors = numberOfConstructors(node.getParent()) > 1; List<ConstructorInitializer> initializers = Lists.newArrayList(); if (superConstructorInvocation != null) { initializers.add(superConstructorInvocation); } String technicalConstructorName = context.generateTechnicalConstructorName(); String constructorDeclName = technicalConstructorName + "_decl"; String constructorImplName = "_" + technicalConstructorName + "_impl"; if (multipleConstructors) { constructorImpl = methodDeclaration(null, identifier(constructorImplName), parameterList, body); } // List<Expression> implInvArgs = Lists.newArrayList(); for (FormalParameter parameter : parameterList.getParameters()) { implInvArgs.add(parameter.getIdentifier()); } Expression implInvocation = methodInvocation(constructorImplName, implInvArgs); Statement conStatement = expressionStatement(implInvocation); Block constructorBody = block(conStatement); SimpleIdentifier nameNode = identifier(constructorDeclName); context.getConstructorDescription(binding).declName = constructorDeclName; context.getConstructorDescription(binding).implName = multipleConstructors ? constructorImplName : constructorDeclName; if (multipleConstructors) { body = blockFunctionBody(constructorBody); } if (isEnumConstructor) { List<FormalParameter> parameters = Lists.newArrayList(); parameters.add(fieldFormalParameter(null, null, ENUM_NAME_FIELD_NAME)); parameters.add(fieldFormalParameter(null, null, ENUM_ORDINAL_FIELD_NAME)); parameters.addAll(parameterList.getParameters()); parameterList = formalParameterList(parameters); } ConstructorDeclaration constructor = constructorDeclaration(translateJavadoc(node), identifier(node.getName().getIdentifier()), nameNode, parameterList, initializers, body); context.putConstructorBinding(constructor, binding); return done(constructor); } else { boolean isStatic = org.eclipse.jdt.core.dom.Modifier.isStatic(node.getModifiers()); SimpleIdentifier dartMethodName = translateSimpleName(node.getName()); MethodDeclaration methodDeclaration = methodDeclaration(translateJavadoc(node), isStatic, (TypeName) translate(node.getReturnType2()), dartMethodName, parameterList, body); context.putNodeBinding(methodDeclaration, binding); if (isNotPublic) { context.putPrivateClassMember(methodDeclaration); } return done(methodDeclaration); } } @Override public boolean visit(org.eclipse.jdt.core.dom.MethodInvocation node) { IMethodBinding binding = node.resolveMethodBinding(); Expression target = translateExpression(node.getExpression()); List<Expression> arguments = translateArguments(binding, node.arguments()); // prepare invocation Identifier name = translate(node.getName()); MethodInvocation invocation; if (name instanceof SimpleIdentifier) { invocation = methodInvocation(target, (SimpleIdentifier) name, arguments); } else { PrefixedIdentifier prefixedName = (PrefixedIdentifier) name; target = prefixedName.getPrefix(); invocation = methodInvocation(target, prefixedName.getIdentifier(), arguments); } // done context.putNodeBinding(invocation, binding); return done(invocation); } @Override public boolean visit(org.eclipse.jdt.core.dom.NullLiteral node) { return done(nullLiteral()); } @Override public boolean visit(org.eclipse.jdt.core.dom.NumberLiteral node) { String token = node.getToken(); if (token.contains(".") || !StringUtils.startsWithIgnoreCase(token, "0x") && (StringUtils.endsWithIgnoreCase(token, "F") || StringUtils.endsWithIgnoreCase(token, "D"))) { token = StringUtils.removeEndIgnoreCase(token, "F"); token = StringUtils.removeEndIgnoreCase(token, "D"); if (!token.contains(".")) { token += ".0"; } return done(new DoubleLiteral(token(TokenType.DOUBLE, token), 0)); } else { token = StringUtils.removeEndIgnoreCase(token, "L"); return done(new IntegerLiteral(token(TokenType.INT, token), BigInteger.valueOf(0))); } } @Override public boolean visit(org.eclipse.jdt.core.dom.ParameterizedType node) { List<TypeName> typeArguments; { List<?> javaTypeArguments = node.typeArguments(); boolean hasMethodTypeVariable = false; for (Object _javaTypeArgument : javaTypeArguments) { org.eclipse.jdt.core.dom.Type javaTypeArgument = (org.eclipse.jdt.core.dom.Type) _javaTypeArgument; ITypeBinding binding = javaTypeArgument.resolveBinding(); if (binding != null && binding.isTypeVariable() && binding.getDeclaringMethod() != null) { hasMethodTypeVariable = true; break; } } if (hasMethodTypeVariable) { typeArguments = null; } else { typeArguments = translateTypeNames(javaTypeArguments); } } ITypeBinding binding = node.resolveBinding(); TypeName typeName = typeName(((TypeName) translate(node.getType())).getName(), typeArguments); context.putNodeBinding(typeName, binding); context.putNodeTypeBinding(typeName, binding); return done(typeName); } @Override public boolean visit(org.eclipse.jdt.core.dom.ParenthesizedExpression node) { Expression expression = translate(node.getExpression()); return done(parenthesizedExpression(expression)); } @Override public boolean visit(org.eclipse.jdt.core.dom.PostfixExpression node) { Expression operand = translate(node.getOperand()); // operator TokenType tokenType = null; org.eclipse.jdt.core.dom.PostfixExpression.Operator javaOperator = node.getOperator(); if (javaOperator == org.eclipse.jdt.core.dom.PostfixExpression.Operator.INCREMENT) { tokenType = TokenType.PLUS_PLUS; } if (javaOperator == org.eclipse.jdt.core.dom.PostfixExpression.Operator.DECREMENT) { tokenType = TokenType.MINUS_MINUS; } // done return done(postfixExpression(operand, tokenType)); } @Override public boolean visit(org.eclipse.jdt.core.dom.PrefixExpression node) { Expression operand = translate(node.getOperand()); // operator TokenType tokenType = null; org.eclipse.jdt.core.dom.PrefixExpression.Operator javaOperator = node.getOperator(); if (javaOperator == org.eclipse.jdt.core.dom.PrefixExpression.Operator.PLUS) { return done(operand); } if (javaOperator == org.eclipse.jdt.core.dom.PrefixExpression.Operator.INCREMENT) { tokenType = TokenType.PLUS_PLUS; } if (javaOperator == org.eclipse.jdt.core.dom.PrefixExpression.Operator.DECREMENT) { tokenType = TokenType.MINUS_MINUS; } if (javaOperator == org.eclipse.jdt.core.dom.PrefixExpression.Operator.MINUS) { tokenType = TokenType.MINUS; } if (javaOperator == org.eclipse.jdt.core.dom.PrefixExpression.Operator.NOT) { tokenType = TokenType.BANG; } if (javaOperator == org.eclipse.jdt.core.dom.PrefixExpression.Operator.COMPLEMENT) { tokenType = TokenType.TILDE; } Assert.isNotNull(tokenType, "No token for: " + javaOperator); // done return done(prefixExpression(tokenType, operand)); } @Override public boolean visit(org.eclipse.jdt.core.dom.PrimitiveType node) { String name = node.toString(); if ("boolean".equals(name)) { name = "bool"; } if ("byte".equals(name) || "char".equals(name) || "short".equals(name) || "long".equals(name)) { name = "int"; } if ("float".equals(name)) { name = "double"; } return done(typeName(name)); } @Override public boolean visit(org.eclipse.jdt.core.dom.QualifiedName node) { PropertyAccess result = propertyAccess(translateExpression(node.getQualifier()), translateSimpleName(node.getName())); context.putNodeBinding(result, node.resolveBinding()); return done(result); } @Override public boolean visit(org.eclipse.jdt.core.dom.ReturnStatement node) { return done(new ReturnStatement(null, translateExpression(node.getExpression()), null)); } @Override public boolean visit(org.eclipse.jdt.core.dom.SimpleName node) { IBinding binding = node.resolveBinding(); SimpleIdentifier result = identifier(node.getIdentifier()); putReference(binding, result); // may be statically imported field, generate PropertyAccess { org.eclipse.jdt.core.dom.StructuralPropertyDescriptor locationInParent = node.getLocationInParent(); if (binding instanceof IVariableBinding) { org.eclipse.jdt.core.dom.IVariableBinding variableBinding = (org.eclipse.jdt.core.dom.IVariableBinding) binding; org.eclipse.jdt.core.dom.ASTNode parent = node.getParent(); if (locationInParent == org.eclipse.jdt.core.dom.EnumConstantDeclaration.ARGUMENTS_PROPERTY || locationInParent == org.eclipse.jdt.core.dom.ClassInstanceCreation.ARGUMENTS_PROPERTY || locationInParent == org.eclipse.jdt.core.dom.MethodInvocation.ARGUMENTS_PROPERTY || locationInParent == org.eclipse.jdt.core.dom.ConstructorInvocation.ARGUMENTS_PROPERTY || locationInParent == org.eclipse.jdt.core.dom.SuperConstructorInvocation.ARGUMENTS_PROPERTY || locationInParent == org.eclipse.jdt.core.dom.Assignment.RIGHT_HAND_SIDE_PROPERTY || locationInParent == org.eclipse.jdt.core.dom.SwitchCase.EXPRESSION_PROPERTY || parent instanceof org.eclipse.jdt.core.dom.InfixExpression || parent instanceof org.eclipse.jdt.core.dom.ConditionalExpression || parent instanceof org.eclipse.jdt.core.dom.ReturnStatement) { ITypeBinding declaringBinding = variableBinding.getDeclaringClass(); ITypeBinding enclosingBinding = getEnclosingTypeBinding(node); if (declaringBinding != null && enclosingBinding != declaringBinding && org.eclipse.jdt.core.dom.Modifier.isStatic(variableBinding.getModifiers())) { SimpleIdentifier target = identifier(declaringBinding.getName()); putReference(declaringBinding, target); return done(propertyAccess(target, result)); } } } } // may be statically imported method, generate PrefixedIdentifier { org.eclipse.jdt.core.dom.StructuralPropertyDescriptor locationInParent = node.getLocationInParent(); if (binding instanceof IMethodBinding) { IMethodBinding methodBinding = (IMethodBinding) binding; if (locationInParent == org.eclipse.jdt.core.dom.MethodInvocation.NAME_PROPERTY && ((org.eclipse.jdt.core.dom.MethodInvocation) node.getParent()).getExpression() == null) { ITypeBinding declaringBinding = methodBinding.getDeclaringClass(); ITypeBinding enclosingBinding = getEnclosingTypeBinding(node); if (declaringBinding != null && enclosingBinding != declaringBinding && org.eclipse.jdt.core.dom.Modifier.isStatic(methodBinding.getModifiers())) { SimpleIdentifier prefix = identifier(declaringBinding.getName()); putReference(declaringBinding, prefix); return done(identifier(prefix, result)); } } } } // done return done(result); } @Override public boolean visit(org.eclipse.jdt.core.dom.SimpleType node) { String name = node.getName().toString(); ITypeBinding binding = node.resolveBinding(); // in Dart we cannot use separate type parameters for methods, so we replace // them with type bounds if (binding != null && binding.isTypeVariable() && binding.getDeclaringMethod() != null) { binding = binding.getErasure(); name = binding.getName(); } // translate name SimpleIdentifier nameNode = identifier(name); putReference(binding, nameNode); { if ("Void".equals(name)) { nameNode = identifier("Object"); } if ("Boolean".equals(name)) { nameNode = identifier("bool"); } if ("Short".equals(name) || "Integer".equals(name) || "Long".equals(name)) { nameNode = identifier("int"); } if ("Float".equals(name) || "Double".equals(name)) { nameNode = identifier("double"); } if ("BigInteger".equals(name)) { nameNode = identifier("int"); } } // done TypeName typeName = typeName(nameNode); context.putNodeBinding(typeName, binding); context.putNodeTypeBinding(typeName, binding); return done(typeName); } @Override public boolean visit(org.eclipse.jdt.core.dom.SingleVariableDeclaration node) { TypeName type = (TypeName) translate(node.getType()); type = listType(type, node.getExtraDimensions()); if (node.isVarargs()) { type = listType(type, 1); } return done(simpleFormalParameter(type, translateSimpleName(node.getName()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.StringLiteral node) { String tokenValue = node.getEscapedValue(); tokenValue = StringUtils.replace(tokenValue, "$", "\\$"); SimpleStringLiteral literal = new SimpleStringLiteral(token(TokenType.STRING, tokenValue), node.getLiteralValue()); context.putNodeTypeBinding(literal, node.resolveTypeBinding()); return done(literal); } @Override public boolean visit(org.eclipse.jdt.core.dom.SuperConstructorInvocation node) { IMethodBinding binding = node.resolveConstructorBinding(); // invoke "impl" List<Expression> arguments = translateArguments(binding, node.arguments()); SuperConstructorInvocation superInvocation = superConstructorInvocation(arguments); context.getConstructorDescription(binding).superInvocations.add(superInvocation); context.putNodeBinding(superInvocation, binding); return done(superInvocation); } @Override public boolean visit(org.eclipse.jdt.core.dom.SuperMethodInvocation node) { IMethodBinding binding = node.resolveMethodBinding(); Expression target = new SuperExpression(null); List<Expression> arguments = translateArguments(binding, node.arguments()); SimpleIdentifier name = translateSimpleName(node.getName()); return done(methodInvocation(target, name, arguments)); } @Override public boolean visit(org.eclipse.jdt.core.dom.SwitchStatement node) { IfStatement mainIfStatement = null; IfStatement targetIfStatement = null; Block ifBlock = null; Expression ifCondition = null; for (Iterator<?> I = node.statements().iterator(); I.hasNext();) { Object javaMember = I.next(); if (javaMember instanceof org.eclipse.jdt.core.dom.SwitchCase) { org.eclipse.jdt.core.dom.SwitchCase javaCase = (org.eclipse.jdt.core.dom.SwitchCase) javaMember; if (javaCase.getExpression() != null) { Expression condition = binaryExpression(translateExpression(node.getExpression()), TokenType.EQ_EQ, translateExpression(javaCase.getExpression())); if (ifCondition == null) { ifCondition = condition; ifBlock = block(); IfStatement ifStatement = ifStatement(condition, ifBlock); if (mainIfStatement == null) { mainIfStatement = ifStatement; } else { targetIfStatement.setElseStatement(ifStatement); } targetIfStatement = ifStatement; } else { ifCondition = binaryExpression(ifCondition, TokenType.BAR_BAR, condition); targetIfStatement.setCondition(ifCondition); } } else { ifBlock = block(); targetIfStatement.setElseStatement(ifBlock); } } else { ifCondition = null; Statement statement = translate((org.eclipse.jdt.core.dom.Statement) javaMember); if (!(statement instanceof BreakStatement)) { ifBlock.getStatements().add(statement); } } } // wrap everything into "while(true)" to handle inner "break" WhileStatement whileStatement = whileStatement(booleanLiteral(true), block(mainIfStatement, breakStatement())); return done(whileStatement); } @Override public boolean visit(org.eclipse.jdt.core.dom.SynchronizedStatement node) { return visit(node.getBody()); } @Override public boolean visit(org.eclipse.jdt.core.dom.ThisExpression node) { return done(thisExpression()); } @Override public boolean visit(org.eclipse.jdt.core.dom.ThrowStatement node) { return done(expressionStatement(throwExpression(translateExpression(node.getExpression())))); } @Override public boolean visit(org.eclipse.jdt.core.dom.TryStatement node) { List<CatchClause> catchClauses = Lists.newArrayList(); for (Iterator<?> I = node.catchClauses().iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.CatchClause javaCatch = (org.eclipse.jdt.core.dom.CatchClause) I.next(); catchClauses.add((CatchClause) translate(javaCatch)); } return done(tryStatement((Block) translate(node.getBody()), catchClauses, (Block) translate(node.getFinally()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.TypeDeclaration node) { ITypeBinding binding = node.resolveBinding(); // prepare name SimpleIdentifier name; { name = translateSimpleName(node.getName()); if (binding != null) { ITypeBinding declaringClass = binding.getDeclaringClass(); if (declaringClass != null) { context.putInnerClassName(name); name.setToken(token(TokenType.IDENTIFIER, declaringClass.getName() + "_" + name.getName())); } } } // interface Token abstractToken = null; if (node.isInterface() || org.eclipse.jdt.core.dom.Modifier.isAbstract(node.getModifiers())) { abstractToken = token(Keyword.ABSTRACT); } // type parameters TypeParameterList typeParams = null; { List<TypeParameter> typeParameters = Lists.newArrayList(); List<?> javaTypeParameters = node.typeParameters(); if (!javaTypeParameters.isEmpty()) { for (Iterator<?> I = javaTypeParameters.iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.TypeParameter javaTypeParameter = (org.eclipse.jdt.core.dom.TypeParameter) I .next(); TypeParameter typeParameter = translate(javaTypeParameter); typeParameters.add(typeParameter); } typeParams = typeParameterList(typeParameters); } } // extends ExtendsClause extendsClause = null; if (node.getSuperclassType() != null) { TypeName superType = translate(node.getSuperclassType()); extendsClause = extendsClause(superType); } // implements ImplementsClause implementsClause = null; if (!node.superInterfaceTypes().isEmpty()) { List<TypeName> interfaces = Lists.newArrayList(); for (Object javaInterface : node.superInterfaceTypes()) { interfaces.add((TypeName) translate((org.eclipse.jdt.core.dom.ASTNode) javaInterface)); } implementsClause = implementsClause(interfaces); } // members List<ClassMember> members = translateBodyDeclarations(node.bodyDeclarations()); for (ClassMember member : members) { if (member instanceof ConstructorDeclaration) { ConstructorDeclaration constructor = (ConstructorDeclaration) member; constructor.setReturnType(name); } } // ClassDeclaration classDeclaration = new ClassDeclaration(translateJavadoc(node), null, abstractToken, null, name, typeParams, extendsClause, null, implementsClause, null, members, null); context.putNodeBinding(classDeclaration, binding); context.putNodeTypeBinding(classDeclaration, binding); context.putNodeTypeBinding(name, binding); return done(classDeclaration); } @Override public boolean visit(org.eclipse.jdt.core.dom.TypeLiteral node) { org.eclipse.jdt.core.dom.Type javaType = node.getType(); Identifier result = null; if (javaType instanceof org.eclipse.jdt.core.dom.SimpleType) { result = ((TypeName) translate(javaType)).getName(); } return done(result); } @Override public boolean visit(org.eclipse.jdt.core.dom.TypeParameter node) { SimpleIdentifier name = translateSimpleName(node.getName()); TypeName bound = null; { List<?> typeBounds = node.typeBounds(); if (typeBounds.size() == 1) { org.eclipse.jdt.core.dom.Type javaBound = (org.eclipse.jdt.core.dom.Type) typeBounds.get(0); bound = (TypeName) translate(javaBound); } } return done(typeParameter(name, bound)); } @Override public boolean visit(org.eclipse.jdt.core.dom.VariableDeclarationFragment node) { VariableDeclaration varDecl = variableDeclaration(translateSimpleName(node.getName()), translateExpression(node.getInitializer())); { IVariableBinding binding = node.resolveBinding(); if (binding != null) { context.putNodeTypeBinding(varDecl, binding.getType()); } } return done(varDecl); } @Override public boolean visit(org.eclipse.jdt.core.dom.VariableDeclarationStatement node) { return done(variableDeclarationStatement( translateVariableDeclarationList(false, node.getType(), node.fragments()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.WhileStatement node) { return done( whileStatement(translateExpression(node.getExpression()), (Statement) translate(node.getBody()))); } @Override public boolean visit(org.eclipse.jdt.core.dom.WildcardType node) { org.eclipse.jdt.core.dom.Type javaBoundType = node.getBound(); if (javaBoundType == null) { return done(typeName("Object")); } else { return done(translate(javaBoundType)); } } private ClassDeclaration declareInnerClass(IMethodBinding constructorBinding, AnonymousClassDeclaration anoClassDeclaration, String innerClassName, String[] additionalParameters) { ITypeBinding superTypeBinding = anoClassDeclaration.resolveBinding().getSuperclass(); ExtendsClause extendsClause = null; ImplementsClause implementsClause = null; { ITypeBinding[] superInterfaces = anoClassDeclaration.resolveBinding().getInterfaces(); if (superInterfaces.length != 0) { superTypeBinding = superInterfaces[0]; TypeName superType = typeName(superInterfaces[0].getName()); putReference(superTypeBinding, (SimpleIdentifier) superType.getName()); implementsClause = implementsClause(superType); } else { TypeName superType = translateTypeName(superTypeBinding); putReference(superTypeBinding, (SimpleIdentifier) superType.getName()); extendsClause = extendsClause(superType); } } ClassDeclaration innerClass = classDeclaration(null, identifier(innerClassName), extendsClause, null, implementsClause, null); artificialUnitDeclarations.add(innerClass); if (extendsClause != null) { List<FormalParameter> parameters = Lists.newArrayList(); List<Expression> arguments = Lists.newArrayList(); // find "super" constructor IMethodBinding superConstructor = null; for (IMethodBinding superMethod : superTypeBinding.getDeclaredMethods()) { if (superMethod.isConstructor()) { if (isSuperConstructor(superMethod, constructorBinding)) { superConstructor = superMethod; // additional parameters for (int i = 0; i < additionalParameters.length / 2; i++) { parameters.add(simpleFormalParameter(null, typeName(additionalParameters[2 * i + 0]), additionalParameters[2 * i + 1])); arguments.add(identifier(additionalParameters[2 * i + 1])); } // "declared" parameters ITypeBinding[] parameterTypes = superMethod.getParameterTypes(); for (int i = 0; i < parameterTypes.length; i++) { TypeName dartParameterType = typeName(parameterTypes[i].getName()); String parameterName = "arg" + i; parameters.add(simpleFormalParameter(dartParameterType, parameterName)); arguments.add(identifier(parameterName)); } // done, we found and processed "super" constructor break; } } } // declare "inner" constructor FormalParameterList parameterList = formalParameterList(parameters); ArgumentList argList = new ArgumentList(null, arguments, null); SuperConstructorInvocation superCI = new SuperConstructorInvocation(null, null, null, argList); context.getConstructorDescription(superConstructor).superInvocations.add(superCI); ConstructorDeclaration innerConstructor = constructorDeclaration(null, null, identifier(innerClassName), null, parameterList, ImmutableList.<ConstructorInitializer>of(superCI), emptyFunctionBody()); innerClass.getMembers().add(innerConstructor); } for (Object javaBodyDeclaration : anoClassDeclaration.bodyDeclarations()) { ClassMember classMember = translate((org.eclipse.jdt.core.dom.ASTNode) javaBodyDeclaration); innerClass.getMembers().add(classMember); } return innerClass; } /** * Set {@link #result} and return <code>false</code> - we don't want normal JDT visiting. */ private boolean done(ASTNode node) { result = node; return false; } private boolean isNumberOrNull(Expression expression) { if (expression instanceof IntegerLiteral || expression instanceof DoubleLiteral || expression instanceof NullLiteral) { return true; } ITypeBinding typeBinding = context.getNodeTypeBinding(expression); if (typeBinding != null) { String name = JavaUtils.getFullyQualifiedName(typeBinding, false); return name.equals("char") || name.equals("short") || name.equals("int") || name.equals("long") || name.equals("float") || name.equals("double") || name.equals("java.lang.Class"); } return false; } private void putReference(org.eclipse.jdt.core.dom.IBinding binding, SimpleIdentifier identifier) { if (binding != null) { binding = JavaUtils.getOriginalBinding(binding); context.putReference(identifier, binding, JavaUtils.getJdtSignature(binding)); } } /** * Recursively translates given {@link org.eclipse.jdt.core.dom.ASTNode} to Dart {@link ASTNode}. * * @return the corresponding Dart {@link ASTNode}, may be <code>null</code> if <code>null</code> * argument was given; not <code>null</code> if argument is not <code>null</code> (if * translation is not implemented, exception will be thrown). */ @SuppressWarnings("unchecked") private <T extends ASTNode> T translate(final org.eclipse.jdt.core.dom.ASTNode node) { if (node == null) { return null; } ExecutionUtils.runRethrow(new RunnableEx() { @Override public void run() throws Exception { Method method = getMostSpecificMethod(node.getClass()); try { method.invoke(SyntaxTranslator.this, node); } catch (InvocationTargetException e) { ExecutionUtils.propagate(e.getCause()); } } }); Assert.isNotNull(result, "No result for: " + node.getClass().getCanonicalName()); T castedResult = (T) result; if (node instanceof org.eclipse.jdt.core.dom.Expression) { context.putNodeTypeBinding(result, ((org.eclipse.jdt.core.dom.Expression) node).resolveTypeBinding()); } result = null; return castedResult; } /** * Translates given {@link List} of {@link org.eclipse.jdt.core.dom.Expression} to the Dart * {@link Expression} list. */ private List<Expression> translateArguments(IMethodBinding binding, List<?> javaArguments) { List<Expression> arguments = translateExpressionList(javaArguments); // may be some of the arguments are var-args if (binding != null && binding.isVarargs()) { int numRequired = binding.getParameterTypes().length - 1; List<Expression> vars = Lists.newArrayList(); for (int i = numRequired; i < arguments.size(); i++) { vars.add(arguments.get(i)); } List<Expression> newArguments = Lists.newArrayList(); newArguments.addAll(arguments.subList(0, numRequired)); newArguments.add(new ListLiteral(null, null, null, vars, null)); arguments = newArguments; } // done return arguments; } private List<ClassMember> translateBodyDeclarations(List<?> javaBodyDeclarations) { List<ClassMember> members = Lists.newArrayList(); for (Iterator<?> I = javaBodyDeclarations.iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.BodyDeclaration javaBodyDecl = (org.eclipse.jdt.core.dom.BodyDeclaration) I .next(); constructorImpl = null; if (javaBodyDecl instanceof org.eclipse.jdt.core.dom.TypeDeclaration || javaBodyDecl instanceof org.eclipse.jdt.core.dom.EnumDeclaration) { ClassDeclaration innerClassDeclaration = translate(javaBodyDecl); artificialUnitDeclarations.add(innerClassDeclaration); } else { ClassMember member = translate(javaBodyDecl); members.add(member); if (constructorImpl != null) { members.add(constructorImpl); } } } return members; } private Expression translateExpression(Object o) { return (Expression) translate((org.eclipse.jdt.core.dom.ASTNode) o); } /** * Translates given {@link List} of {@link org.eclipse.jdt.core.dom.Expression} to the * {@link List} of {@link Expression}s. */ private List<Expression> translateExpressionList(List<?> javaArguments) { List<Expression> arguments = Lists.newArrayList(); for (Iterator<?> I = javaArguments.iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.Expression javaArg = (org.eclipse.jdt.core.dom.Expression) I.next(); Expression dartArg = translate(javaArg); arguments.add(dartArg); } return arguments; } private Comment translateJavadoc(org.eclipse.jdt.core.dom.BodyDeclaration node) { return (Comment) translate(node.getJavadoc()); } private SimpleIdentifier translateSimpleName(org.eclipse.jdt.core.dom.SimpleName name) { return translate(name); } private TypeName translateTypeName(ITypeBinding binding) { if (binding != null) { if (binding.isArray()) { return typeName(identifier("List"), translateTypeName(binding.getComponentType())); } String name = binding.getName(); name = StringUtils.substringBefore(name, "<"); if (JavaUtils.isTypeNamed(binding, "java.util.ArrayList")) { name = "List"; } if (JavaUtils.isTypeNamed(binding, "java.lang.Void")) { name = "Object"; } if ("boolean".equals(name)) { return typeName("bool"); } List<TypeName> arguments = Lists.newArrayList(); for (ITypeBinding typeArgument : binding.getTypeArguments()) { arguments.add(translateTypeName(typeArgument)); } TypeName result = typeName(identifier(name), arguments); context.putNodeTypeBinding(result, binding); context.putNodeTypeBinding(result.getName(), binding); putReference(binding, (SimpleIdentifier) result.getName()); return result; } throw new IllegalArgumentException("" + binding); } /** * Translates given {@link List} of {@link org.eclipse.jdt.core.dom.Type} to the * {@link TypeArgumentList}. */ private List<TypeName> translateTypeNames(List<?> javaTypes) { List<TypeName> typeNames = Lists.newArrayList(); for (Iterator<?> I = javaTypes.iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.Type javaType = (org.eclipse.jdt.core.dom.Type) I.next(); TypeName dartType = translate(javaType); typeNames.add(dartType); } return typeNames; } /** * Translates given {@link List} of {@link org.eclipse.jdt.core.dom.VariableDeclarationFragment} * to the {@link VariableDeclarationList}. */ private VariableDeclarationList translateVariableDeclarationList(boolean isFinal, org.eclipse.jdt.core.dom.Type javaType, List<?> javaVars) { List<VariableDeclaration> variableDeclarations = Lists.newArrayList(); for (Iterator<?> I = javaVars.iterator(); I.hasNext();) { org.eclipse.jdt.core.dom.VariableDeclarationFragment javaFragment = (org.eclipse.jdt.core.dom.VariableDeclarationFragment) I .next(); VariableDeclaration var = translate(javaFragment); variableDeclarations.add(var); } return variableDeclarationList(isFinal ? Keyword.FINAL : null, (TypeName) translate(javaType), variableDeclarations); } }