/*
* Copyright (c) 2013, 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.processor;
import com.google.common.collect.Lists;
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.AstNode;
import com.google.dart.engine.ast.BinaryExpression;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.Expression;
import com.google.dart.engine.ast.InstanceCreationExpression;
import com.google.dart.engine.ast.IntegerLiteral;
import com.google.dart.engine.ast.InterpolationElement;
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.ParenthesizedExpression;
import com.google.dart.engine.ast.PrefixExpression;
import com.google.dart.engine.ast.PropertyAccess;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.SimpleStringLiteral;
import com.google.dart.engine.ast.StringInterpolation;
import com.google.dart.engine.ast.SuperConstructorInvocation;
import com.google.dart.engine.ast.TypeName;
import com.google.dart.engine.ast.VariableDeclaration;
import com.google.dart.engine.ast.visitor.GeneralizingAstVisitor;
import com.google.dart.engine.scanner.Keyword;
import com.google.dart.engine.scanner.TokenType;
import com.google.dart.java2dart.Context;
import com.google.dart.java2dart.util.JavaUtils;
import static com.google.dart.java2dart.util.AstFactory.argumentList;
import static com.google.dart.java2dart.util.AstFactory.assignmentExpression;
import static com.google.dart.java2dart.util.AstFactory.binaryExpression;
import static com.google.dart.java2dart.util.AstFactory.booleanLiteral;
import static com.google.dart.java2dart.util.AstFactory.identifier;
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.interpolationExpression;
import static com.google.dart.java2dart.util.AstFactory.interpolationString;
import static com.google.dart.java2dart.util.AstFactory.methodInvocation;
import static com.google.dart.java2dart.util.AstFactory.namedExpression;
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.string;
import static com.google.dart.java2dart.util.AstFactory.thisExpression;
import static com.google.dart.java2dart.util.AstFactory.typeName;
import static com.google.dart.java2dart.util.TokenFactory.token;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import java.util.List;
/**
* {@link SemanticProcessor} for Java <code>Object</code>.
*/
public class ObjectSemanticProcessor extends SemanticProcessor {
private static List<Expression> gatherBinaryExpressions(BinaryExpression binary) {
List<Expression> expressions = Lists.newArrayList();
{
Expression left = binary.getLeftOperand();
if (left instanceof BinaryExpression) {
expressions.addAll(gatherBinaryExpressions((BinaryExpression) left));
} else {
expressions.add(left);
}
}
{
Expression right = binary.getRightOperand();
expressions.add(right);
}
return expressions;
}
private static boolean hasStringObjects(Context context, List<Expression> expressions) {
for (Expression expression : expressions) {
ITypeBinding binding = context.getNodeTypeBinding(expression);
if (JavaUtils.isTypeNamed(binding, "java.lang.String")) {
return true;
}
}
return false;
}
public ObjectSemanticProcessor(Context context) {
super(context);
}
@Override
public void process(CompilationUnit unit) {
unit.accept(new GeneralizingAstVisitor<Void>() {
@Override
public Void visitAsExpression(AsExpression node) {
super.visitAsExpression(node);
Expression expression = node.getExpression();
TypeName targetTypeName = node.getType();
ITypeBinding expressionTypeBinding = context.getNodeTypeBinding(expression);
ITypeBinding targetTypeBinding = context.getNodeTypeBinding(targetTypeName);
if (JavaUtils.isTypeNamed(expressionTypeBinding, "double")) {
if (JavaUtils.isTypeNamed(targetTypeBinding, "int")
|| JavaUtils.isTypeNamed(targetTypeBinding, "long")) {
AstNode nodeToReplace = node;
AstNode parent = node.getParent();
if (parent instanceof ParenthesizedExpression) {
nodeToReplace = parent;
}
replaceNode(nodeToReplace, methodInvocation(expression, identifier("toInt")));
return null;
}
}
return null;
}
@Override
public Void visitAssignmentExpression(AssignmentExpression node) {
super.visitAssignmentExpression(node);
if (node.getOperator().getType() == TokenType.EQ) {
Expression leftExpr = node.getLeftHandSide();
Expression rightExpr = node.getRightHandSide();
ITypeBinding leftBinding = context.getNodeTypeBinding(leftExpr);
ITypeBinding rightBinding = context.getNodeTypeBinding(rightExpr);
if (JavaUtils.isTypeNamed(leftBinding, "java.lang.CharSequence")
&& JavaUtils.isTypeNamed(rightBinding, "java.lang.String")) {
node.setRightHandSide(instanceCreationExpression(
Keyword.NEW,
typeName("CharSequence"),
rightExpr));
return null;
}
}
// Dart has no "bool |=" operator
if (node.getOperator().getType() == TokenType.BAR_EQ) {
Expression leftExpr = node.getLeftHandSide();
ITypeBinding argTypeBinding = context.getNodeTypeBinding(leftExpr);
if (JavaUtils.isTypeNamed(argTypeBinding, "boolean")) {
Expression rightExpr = node.getRightHandSide();
replaceNode(
node,
assignmentExpression(
leftExpr,
TokenType.EQ,
methodInvocation("javaBooleanOr", leftExpr, rightExpr)));
return null;
}
}
// Dart has no "bool &=" operator
if (node.getOperator().getType() == TokenType.AMPERSAND_EQ) {
Expression leftExpr = node.getLeftHandSide();
ITypeBinding argTypeBinding = context.getNodeTypeBinding(leftExpr);
if (JavaUtils.isTypeNamed(argTypeBinding, "boolean")) {
Expression rightExpr = node.getRightHandSide();
replaceNode(
node,
assignmentExpression(
leftExpr,
TokenType.EQ,
methodInvocation("javaBooleanAnd", leftExpr, rightExpr)));
return null;
}
}
// String += 'c'
if (node.getOperator().getType() == TokenType.PLUS_EQ) {
Expression leftExpr = node.getLeftHandSide();
ITypeBinding argTypeBinding = context.getNodeTypeBinding(leftExpr);
if (JavaUtils.isTypeNamed(argTypeBinding, "java.lang.String")) {
Expression rightExpr = node.getRightHandSide();
replaceCharWithString(rightExpr);
return null;
}
}
return null;
}
@Override
public Void visitBinaryExpression(BinaryExpression node) {
if (node.getOperator().getType() == TokenType.PLUS) {
List<Expression> expressions = gatherBinaryExpressions(node);
if (hasStringObjects(context, expressions)) {
// try to rewrite each expression
for (Expression expression : expressions) {
expression.accept(this);
}
expressions = gatherBinaryExpressions(node);
// compose interpolation using expressions
List<InterpolationElement> elements = Lists.newArrayList();
elements.add(interpolationString("\"", ""));
for (Expression expression : expressions) {
if (expression instanceof SimpleStringLiteral) {
SimpleStringLiteral literal = (SimpleStringLiteral) expression;
String value = literal.getValue();
String lexeme = StringUtils.strip(literal.getLiteral().getLexeme(), "\"");
elements.add(interpolationString(lexeme, value));
} else if (expression instanceof IntegerLiteral
&& JavaUtils.isTypeNamed(context.getNodeTypeBinding(expression), "char")) {
String value = "" + (char) ((IntegerLiteral) expression).getValue().intValue();
elements.add(interpolationString(value, value));
} else if (JavaUtils.isTypeNamed(context.getNodeTypeBinding(expression), "char")) {
InstanceCreationExpression newString = instanceCreationExpression(
Keyword.NEW,
typeName("String"),
"fromCharCode",
expression);
elements.add(interpolationExpression(newString));
} else {
elements.add(interpolationExpression(expression));
}
}
elements.add(interpolationString("\"", ""));
StringInterpolation interpolation = string(elements);
replaceNode(node, interpolation);
return null;
}
}
// in Java "true | false" will compute both operands
if (node.getOperator().getType() == TokenType.BAR) {
ITypeBinding argTypeBinding = context.getNodeTypeBinding(node.getLeftOperand());
super.visitBinaryExpression(node);
if (JavaUtils.isTypeNamed(argTypeBinding, "boolean")) {
replaceNode(
node,
methodInvocation("javaBooleanOr", node.getLeftOperand(), node.getRightOperand()));
return null;
}
}
// in Java "true & false" will compute both operands
if (node.getOperator().getType() == TokenType.AMPERSAND) {
ITypeBinding argTypeBinding = context.getNodeTypeBinding(node.getLeftOperand());
super.visitBinaryExpression(node);
if (JavaUtils.isTypeNamed(argTypeBinding, "boolean")) {
replaceNode(
node,
methodInvocation("javaBooleanAnd", node.getLeftOperand(), node.getRightOperand()));
return null;
}
}
// super
super.visitBinaryExpression(node);
// done
return null;
}
@Override
public Void visitInstanceCreationExpression(InstanceCreationExpression node) {
super.visitInstanceCreationExpression(node);
ITypeBinding typeBinding = context.getNodeTypeBinding(node);
IMethodBinding binding = (IMethodBinding) context.getNodeBinding(node);
List<Expression> args = node.getArgumentList().getArguments();
String typeSimpleName = node.getConstructorName().getType().getName().getName();
if (JavaUtils.isTypeNamed(typeBinding, "java.lang.StringBuilder")) {
args.clear();
return null;
}
ArgumentList newArguments = fixConstructorArguments(args, binding);
if (newArguments != null) {
node.setArgumentList(newArguments);
} else if (typeSimpleName.equals("int")) {
if (args.size() == 1) {
replaceNode(node, methodInvocation(identifier("int"), "parse", args.get(0)));
} else {
replaceNode(
node,
methodInvocation(
identifier("int"),
"parse",
args.get(0),
namedExpression("radix", args.get(1))));
}
}
return null;
}
@Override
public Void visitMethodDeclaration(MethodDeclaration node) {
if (node.getName() instanceof SimpleIdentifier) {
String name = node.getName().getName();
if (name.equals("hashCode")) {
node.setOperatorKeyword(token(Keyword.GET));
node.setParameters(null);
}
if (name.equals("equals") && node.getParameters().getParameters().size() == 1) {
node.setOperatorKeyword(token(Keyword.OPERATOR));
node.setName(identifier("=="));
}
}
return super.visitMethodDeclaration(node);
}
@Override
public Void visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
SimpleIdentifier nameNode = node.getMethodName();
String name = nameNode.getName();
Expression target = node.getTarget();
NodeList<Expression> args = node.getArgumentList().getArguments();
// System -> JavaSystem
if (target instanceof SimpleIdentifier) {
SimpleIdentifier targetIdentifier = (SimpleIdentifier) target;
if (targetIdentifier.getName().equals("System")) {
targetIdentifier.setToken(token("JavaSystem"));
}
if (isMethodInClass(node, "getProperty", "java.lang.System")
|| isMethodInClass(node, "getenv", "java.lang.System")) {
targetIdentifier.setToken(token("JavaSystemIO"));
}
}
//
if (args.isEmpty()) {
if ("hashCode".equals(name) || isMethodInClass(node, "length", "java.lang.String")
|| isMethodInClass(node, "length", "java.lang.CharSequence")
|| isMethodInClass(node, "isEmpty", "java.lang.String")
|| isMethodInClass(node, "name", "java.lang.Enum")
|| isMethodInClass(node, "ordinal", "java.lang.Enum")
|| isMethodInClass(node, "values", "java.lang.Enum")
|| isMethodInClass(node, "bitLength", "java.math.BigInteger")) {
replaceNode(node, propertyAccess(target, nameNode));
return null;
}
if ("getClass".equals(name)) {
replaceNode(node, propertyAccess(target, "runtimeType"));
return null;
}
if (isMethodInClass(node, "getName", "java.lang.Class")
|| isMethodInClass(node, "getSimpleName", "java.lang.Class")) {
nameNode.setToken(token("toString"));
return null;
}
}
if (name.equals("equals") && args.size() == 1) {
AstNode parent = node.getParent();
if (target == null) {
target = thisExpression();
}
if (parent instanceof PrefixExpression
&& ((PrefixExpression) parent).getOperator().getType() == TokenType.BANG) {
replaceNode(parent, binaryExpression(target, TokenType.BANG_EQ, args.get(0)));
} else {
if (isMethodInClass(node, "equals", "java.util.Set")) {
replaceNode(node, methodInvocation("javaSetEquals", target, args.get(0)));
} else {
replaceNode(node, binaryExpression(target, TokenType.EQ_EQ, args.get(0)));
}
}
return null;
}
if (name.equals("clone")) {
ITypeBinding targetBinding = context.getNodeTypeBinding(target);
if (targetBinding.isArray()) {
ITypeBinding componentType = targetBinding.getComponentType();
if (componentType.isTypeVariable()) {
componentType = componentType.getTypeBounds()[0];
}
replaceNode(
node,
instanceCreationExpression(
Keyword.NEW,
typeName("List", typeName(componentType.getName())),
"from",
target));
return null;
}
}
// prepare binding
IMethodBinding binding = (IMethodBinding) context.getNodeBinding(node);
// analyze invocations
if (isMethodInClass(node, "getMessage", "java.lang.Throwable")) {
nameNode.setToken(token("toString"));
return null;
}
if (isMethodInClass(node, "getCause", "java.lang.Throwable")) {
replaceNode(node, propertyAccess(target, "cause"));
return null;
}
if (isMethodInClass(node, "printStackTrace", "java.lang.Throwable")) {
replaceNode(node, methodInvocation("print", target));
return null;
}
if (isMethodInClass(node, "isInstance", "java.lang.Class")) {
replaceNode(node, methodInvocation("isInstanceOf", args.get(0), target));
return null;
}
if (isMethodInClass(node, "charAt", "java.lang.String")) {
nameNode.setToken(token("codeUnitAt"));
return null;
}
if (isMethodInClass2(node, "replace(char,char)", "java.lang.String")) {
nameNode.setToken(token("replaceAll"));
replaceCharWithString(args.get(0));
replaceCharWithString(args.get(1));
return null;
}
if (isMethodInClass2(
node,
"replace(java.lang.CharSequence,java.lang.CharSequence)",
"java.lang.String")) {
nameNode.setToken(token("replaceAll"));
return null;
}
if (isMethodInClass2(node, "contains(java.lang.CharSequence)", "java.lang.String")) {
return null;
}
if (isMethodInClass(node, "equalsIgnoreCase", "java.lang.String")) {
replaceNode(node, methodInvocation("javaStringEqualsIgnoreCase", target, args.get(0)));
return null;
}
if (isMethodInClass(node, "regionMatches", "java.lang.String")) {
replaceNode(
node,
methodInvocation(
"javaStringRegionMatches",
target,
args.get(0),
args.get(1),
args.get(2),
args.get(3)));
return null;
}
if (isMethodInClass(node, "indexOf", "java.lang.String")
|| isMethodInClass(node, "lastIndexOf", "java.lang.String")) {
replaceCharWithString(args.get(0));
if (args.size() == 2) {
replaceNode(
node,
methodInvocation(identifier("JavaString"), name, target, args.get(0), args.get(1)));
}
return null;
}
if (isMethodInClass2(node, "valueOf(char)", "java.lang.String")) {
replaceNode(
node,
instanceCreationExpression(
Keyword.NEW,
typeName("String"),
"fromCharCode",
args.get(0)));
return null;
}
if (isMethodInClass2(node, "concat(java.lang.String)", "java.lang.String")) {
replaceNode(node, binaryExpression(target, TokenType.PLUS, args.get(0)));
return null;
}
if (isMethodInClass(node, "print", "java.io.PrintWriter")) {
if (binding != null && binding.getParameterTypes().length >= 1
&& binding.getParameterTypes()[0].getName().equals("char")) {
char c = (char) ((IntegerLiteral) args.get(0)).getValue().intValue();
replaceNode(args.get(0), string("" + c));
}
return null;
}
if (isMethodInClass2(node, "println()", "java.io.PrintWriter")) {
nameNode.setToken(token("newLine"));
return null;
}
if (isMethodInClass2(node, "println(java.lang.String)", "java.io.PrintWriter")) {
nameNode.setToken(token("println"));
return null;
}
if (isMethodInClass2(node, "startsWith(java.lang.String,int)", "java.lang.String")) {
replaceNode(
node,
methodInvocation(
identifier("JavaString"),
"startsWithBefore",
target,
args.get(0),
args.get(1)));
return null;
}
if (isMethodInClass(node, "format", "java.lang.String")) {
replaceNode(target, identifier("JavaString"));
return null;
}
if (isMethodInClass(node, "charAt", "java.lang.CharSequence")) {
nameNode.setToken(token("codeUnitAt"));
return null;
}
if (isMethodInClass(node, "subSequence", "java.lang.CharSequence")) {
nameNode.setToken(token("substring"));
return null;
}
if (isMethodInClass(node, "compile", "java.util.regex.Pattern")) {
replaceNode(
node,
instanceCreationExpression(Keyword.NEW, typeName("RegExp"), args.get(0)));
return null;
}
if (isMethodInClass(node, "matcher", "java.util.regex.Pattern")) {
replaceNode(
node,
instanceCreationExpression(
Keyword.NEW,
typeName("JavaPatternMatcher"),
target,
args.get(0)));
return null;
}
if (name.equals("longValue") && target instanceof MethodInvocation) {
MethodInvocation node2 = (MethodInvocation) target;
if (isMethodInClass(node2, "floor", "java.lang.Math")) {
NodeList<Expression> args2 = node2.getArgumentList().getArguments();
if (args2.size() == 1 && args2.get(0) instanceof BinaryExpression) {
BinaryExpression binary = (BinaryExpression) args2.get(0);
if (binary.getOperator().getType() == TokenType.SLASH) {
replaceNode(
node,
binaryExpression(
binary.getLeftOperand(),
TokenType.TILDE_SLASH,
binary.getRightOperand()));
return null;
}
}
}
}
if (isMethodInClass(node, "valueOf", "java.lang.Integer")
|| isMethodInClass(node, "valueOf", "java.lang.Long")
|| isMethodInClass(node, "valueOf", "java.lang.Double")
|| isMethodInClass(node, "valueOf", "java.math.BigInteger")) {
replaceNode(node, args.get(0));
return null;
}
if (isMethodInClass(node, "parseInt", "java.lang.Integer")) {
node.setTarget(identifier("int"));
nameNode.setToken(token("parse"));
if (args.size() == 2) {
args.set(1, namedExpression("radix", args.get(1)));
}
return null;
}
if (isMethodInClass(node, "parseDouble", "java.lang.Double")) {
node.setTarget(identifier("double"));
nameNode.setToken(token("parse"));
return null;
}
if (isMethodInClass2(node, "toString(double)", "java.lang.Double")
|| isMethodInClass2(node, "toString(int)", "java.lang.Integer")
|| isMethodInClass2(node, "toString(long)", "java.lang.Long")) {
replaceNode(node, methodInvocation(args.get(0), "toString"));
return null;
}
if (isMethodInClass2(node, "toString(int,int)", "java.lang.Integer")
|| isMethodInClass2(node, "toString(long,int)", "java.lang.Long")) {
replaceNode(node, methodInvocation(args.get(0), "toRadixString", args.get(1)));
return null;
}
if (isMethodInClass(node, "booleanValue", "java.lang.Boolean")
|| isMethodInClass(node, "doubleValue", "java.lang.Double")
|| isMethodInClass(node, "intValue", "java.lang.Integer")
|| isMethodInClass(node, "longValue", "java.lang.Long")
|| isMethodInClass(node, "intValue", "java.math.BigInteger")) {
replaceNode(node, target);
return null;
}
if (isMethodInClass(node, "intValue", "java.lang.Number")) {
nameNode.setToken(token("toInt"));
return null;
}
if (isMethodInClass(node, "doubleValue", "java.math.BigInteger")) {
nameNode.setToken(token("toDouble"));
return null;
}
{
TokenType tokenType = null;
if (isMethodInClass(node, "and", "java.math.BigInteger")) {
tokenType = TokenType.AMPERSAND;
} else if (isMethodInClass(node, "or", "java.math.BigInteger")) {
tokenType = TokenType.BAR;
} else if (isMethodInClass(node, "xor", "java.math.BigInteger")) {
tokenType = TokenType.CARET;
} else if (isMethodInClass(node, "add", "java.math.BigInteger")) {
tokenType = TokenType.PLUS;
} else if (isMethodInClass(node, "subtract", "java.math.BigInteger")) {
tokenType = TokenType.MINUS;
} else if (isMethodInClass(node, "multiply", "java.math.BigInteger")) {
tokenType = TokenType.STAR;
} else if (isMethodInClass(node, "divide", "java.math.BigInteger")) {
tokenType = TokenType.TILDE_SLASH;
} else if (isMethodInClass(node, "shiftLeft", "java.math.BigInteger")) {
tokenType = TokenType.LT_LT;
} else if (isMethodInClass(node, "shiftRight", "java.math.BigInteger")) {
tokenType = TokenType.GT_GT;
}
if (tokenType != null) {
replaceNode(node, binaryExpression(target, tokenType, args.get(0)));
return null;
}
}
{
TokenType tokenType = null;
if (isMethodInClass(node, "not", "java.math.BigInteger")) {
tokenType = TokenType.TILDE;
} else if (isMethodInClass(node, "negate", "java.math.BigInteger")) {
tokenType = TokenType.MINUS;
}
if (tokenType != null) {
replaceNode(node, prefixExpression(tokenType, target));
return null;
}
}
if (isMethodInClass2(node, "append(char)", "java.lang.StringBuilder")) {
replaceNode(nameNode, identifier("appendChar"));
return null;
}
if (isMethodInClass(node, "length", "java.lang.AbstractStringBuilder")) {
replaceNode(node, propertyAccess(target, nameNode));
return null;
}
if (isMethodInClass(node, "setLength", "java.lang.AbstractStringBuilder")) {
nameNode.setToken(token("length"));
replaceNode(
node,
assignmentExpression(propertyAccess(target, nameNode), TokenType.EQ, args.get(0)));
return null;
}
return null;
}
@Override
public Void visitPropertyAccess(PropertyAccess node) {
Expression target = node.getTarget();
ITypeBinding targetTypeBinding = context.getNodeTypeBinding(target);
if (target instanceof SimpleIdentifier) {
String targetName = ((SimpleIdentifier) target).getName();
if (targetName.equals("Boolean")) {
boolean value = node.getPropertyName().getName().equals("TRUE");
replaceNode(node, booleanLiteral(value));
return null;
}
if (targetName.equals("Integer")) {
int value;
if (node.getPropertyName().getName().equals("MIN_VALUE")) {
value = Integer.MIN_VALUE;
} else {
value = Integer.MAX_VALUE;
}
replaceNode(node, integer(value));
return null;
}
if (JavaUtils.isTypeNamed(targetTypeBinding, "java.math.BigInteger")) {
if (node.getPropertyName().getName().equals("ZERO")) {
replaceNode(node, integer(0));
return null;
}
}
}
return super.visitPropertyAccess(node);
}
@Override
public Void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
super.visitSuperConstructorInvocation(node);
NodeList<Expression> args = node.getArgumentList().getArguments();
IMethodBinding binding = (IMethodBinding) context.getNodeBinding(node);
if (isMethodInExactClass(binding, "<init>(java.lang.Throwable)", "java.lang.Exception")) {
node.setConstructorName(identifier("withCause"));
}
ArgumentList newArguments = fixConstructorArguments(args, binding);
if (newArguments != null) {
node.setArgumentList(newArguments);
}
return null;
}
@Override
public Void visitTypeName(TypeName node) {
ITypeBinding typeBinding = (ITypeBinding) context.getNodeBinding(node);
// replace by name
if (node.getName() instanceof SimpleIdentifier) {
SimpleIdentifier nameNode = (SimpleIdentifier) node.getName();
String name = nameNode.getName();
// Exception -> JavaException
if (JavaUtils.isTypeNamed(typeBinding, "java.lang.Exception")) {
replaceNode(nameNode, identifier("JavaException"));
}
if (JavaUtils.isTypeNamed(typeBinding, "java.lang.Throwable")) {
replaceNode(nameNode, identifier("Exception"));
}
if (JavaUtils.isTypeNamed(typeBinding, "java.lang.IndexOutOfBoundsException")) {
replaceNode(nameNode, identifier("RangeError"));
}
if (JavaUtils.isTypeNamed(typeBinding, "java.lang.NumberFormatException")) {
replaceNode(nameNode, identifier("FormatException"));
}
// StringBuilder -> JavaStringBuilder
if (name.equals("StringBuilder")) {
replaceNode(nameNode, identifier("JavaStringBuilder"));
}
if (name.equals("CharSequence")) {
replaceNode(nameNode, identifier("String"));
}
// java.util.regex.*
if (JavaUtils.isTypeNamed(typeBinding, "java.util.regex.Pattern")) {
replaceNode(nameNode, identifier("RegExp"));
}
if (JavaUtils.isTypeNamed(typeBinding, "java.util.regex.Matcher")) {
replaceNode(nameNode, identifier("JavaPatternMatcher"));
}
// Class<T> -> Type
if (name.equals("Class")) {
replaceNode(node, typeName("Type"));
}
}
// done
return super.visitTypeName(node);
}
@Override
public Void visitVariableDeclaration(VariableDeclaration node) {
super.visitVariableDeclaration(node);
Expression initializer = node.getInitializer();
ITypeBinding leftBinding = context.getNodeTypeBinding(node);
ITypeBinding rightBinding = context.getNodeTypeBinding(initializer);
if (JavaUtils.isTypeNamed(leftBinding, "java.lang.CharSequence")
&& JavaUtils.isTypeNamed(rightBinding, "java.lang.String")) {
node.setInitializer(instanceCreationExpression(
Keyword.NEW,
typeName("CharSequence"),
initializer));
return null;
}
return null;
}
private ArgumentList fixConstructorArguments(List<Expression> args, IMethodBinding binding) {
if (isMethodInExactClass(
binding,
"<init>(java.lang.Throwable)",
"java.lang.RuntimeException")) {
return argumentList(namedExpression("cause", args.get(0)));
}
if (isMethodInExactClass(binding, "<init>(java.lang.String)", "java.lang.RuntimeException")) {
return argumentList(namedExpression("message", args.get(0)));
}
if (isMethodInExactClass(
binding,
"<init>(java.lang.String,java.lang.Throwable)",
"java.lang.RuntimeException")) {
return argumentList(
namedExpression("message", args.get(0)),
namedExpression("cause", args.get(0)));
}
return null;
}
private void replaceCharWithString(Expression x) {
// should by 'char'
ITypeBinding typeBinding = context.getNodeTypeBinding(x);
if (!JavaUtils.isTypeNamed(typeBinding, "char")) {
return;
}
// replace literal
if (x instanceof IntegerLiteral) {
IntegerLiteral literal = (IntegerLiteral) x;
String str = String.valueOf((char) literal.getValue().intValue());
if (str.equals("\\")) {
str = "\\\\";
}
replaceNode(x, string(str));
return;
}
// replace expression
SimpleIdentifier placeholder = identifier("ph");
InstanceCreationExpression newString = instanceCreationExpression(
Keyword.NEW,
typeName("String"),
"fromCharCode",
placeholder);
replaceNode(x, newString);
replaceNode(placeholder, x);
}
});
}
}