/* * 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.AssignmentExpression; import com.google.dart.engine.ast.ClassDeclaration; import com.google.dart.engine.ast.ClassMember; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.ast.CompilationUnitMember; import com.google.dart.engine.ast.Expression; import com.google.dart.engine.ast.ExpressionFunctionBody; import com.google.dart.engine.ast.ExpressionStatement; import com.google.dart.engine.ast.FunctionExpression; import com.google.dart.engine.ast.IndexExpression; import com.google.dart.engine.ast.InstanceCreationExpression; import com.google.dart.engine.ast.MethodDeclaration; import com.google.dart.engine.ast.MethodInvocation; import com.google.dart.engine.ast.SimpleIdentifier; import com.google.dart.engine.ast.TypeName; 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 com.google.dart.java2dart.util.TokenFactory; import static com.google.dart.java2dart.util.AstFactory.assignmentExpression; import static com.google.dart.java2dart.util.AstFactory.functionExpression; import static com.google.dart.java2dart.util.AstFactory.functionExpressionInvocation; import static com.google.dart.java2dart.util.AstFactory.identifier; 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.methodInvocation; import static com.google.dart.java2dart.util.AstFactory.propertyAccess; import static com.google.dart.java2dart.util.AstFactory.typeName; import static com.google.dart.java2dart.util.TokenFactory.token; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import java.util.List; /** * {@link SemanticProcessor} for Java <code>java.util</code> collections. */ public class CollectionSemanticProcessor extends SemanticProcessor { public CollectionSemanticProcessor(Context context) { super(context); } @Override public void process(final CompilationUnit unit) { unit.accept(new GeneralizingAstVisitor<Void>() { @Override public Void visitCompilationUnit(CompilationUnit node) { List<CompilationUnitMember> declarations = Lists.newArrayList(unit.getDeclarations()); for (CompilationUnitMember member : declarations) { member.accept(this); } return null; } @Override public Void visitInstanceCreationExpression(InstanceCreationExpression node) { super.visitInstanceCreationExpression(node); Object binding = context.getNodeBinding(node); if (binding instanceof IMethodBinding) { IMethodBinding methodBinding = (IMethodBinding) binding; ITypeBinding declaringClass = methodBinding.getDeclaringClass(); // new HashSet(Map) -> new Set.from(Map) if (isMethodInClass2(methodBinding, "<init>(java.util.Collection)", "java.util.HashSet")) { node.getConstructorName().setName(identifier("from")); return null; } // new HashSet(5) -> new HashSet() if (JavaUtils.getQualifiedName(declaringClass).equals("java.util.HashSet")) { node.getArgumentList().getArguments().clear(); return null; } // new HashMap(Map) -> new HashMap.from(Map) if (isMethodInClass2(methodBinding, "<init>(java.util.Map)", "java.util.HashMap")) { node.getConstructorName().setName(identifier("from")); return null; } // new HashMap(5) -> new HashMap() if (JavaUtils.getQualifiedName(declaringClass).equals("java.util.HashMap")) { ((SimpleIdentifier) node.getConstructorName().getType().getName()).setToken(token("HashMap")); node.getArgumentList().getArguments().clear(); return null; } // new ArrayList(Collection) -> new List.from(Iterable) if (isMethodInClass2(methodBinding, "<init>(java.util.Collection)", "java.util.ArrayList")) { node.getConstructorName().setName(identifier("from")); return null; } // new ArrayList(5) -> new List() if (isMethodInClass2(methodBinding, "<init>(int)", "java.util.ArrayList")) { node.getArgumentList().getArguments().clear(); return null; } // translate java.util.Comparator to function expression if (methodBinding.isConstructor() && declaringClass.isAnonymous()) { ITypeBinding[] intfs = declaringClass.getInterfaces(); if (intfs.length == 1 && JavaUtils.getQualifiedName(intfs[0]).equals("java.util.Comparator")) { ClassDeclaration innerClass = context.getAnonymousDeclaration(node); if (innerClass != null) { unit.getDeclarations().remove(innerClass); List<ClassMember> innerMembers = innerClass.getMembers(); MethodDeclaration compareMethod = (MethodDeclaration) innerMembers.get(0); FunctionExpression functionExpression = functionExpression( compareMethod.getParameters(), compareMethod.getBody()); // don't add ";" at the end of ExpressionFunctionBody if (compareMethod.getBody() instanceof ExpressionFunctionBody) { ExpressionFunctionBody expressionFunctionBody = (ExpressionFunctionBody) compareMethod.getBody(); expressionFunctionBody.setSemicolon(null); } // do replace replaceNode(node, functionExpression); } } } } // done return null; } @Override public Void visitMethodInvocation(MethodInvocation node) { super.visitMethodInvocation(node); Expression target = node.getTarget(); SimpleIdentifier nameNode = node.getMethodName(); List<Expression> args = node.getArgumentList().getArguments(); if (isMethodInClass(node, "compare", "java.util.Comparator")) { replaceNode(node, functionExpressionInvocation(target, args)); return null; } if (isMethodInClass(node, "size", "java.util.Collection") || isMethodInClass(node, "size", "java.util.Map")) { replaceNode(node, propertyAccess(target, nameNode)); nameNode.setToken(token("length")); return null; } if (isMethodInClass(node, "isEmpty", "java.util.Collection")) { replaceNode(node, propertyAccess(target, nameNode)); return null; } if (isMethodInClass(node, "get", "java.util.List") || isMethodInClass(node, "get", "java.util.Map")) { replaceNode(node, indexExpression(target, args.get(0))); return null; } if (isMethodInClass(node, "toArray", "java.util.Collection")) { replaceNode( node, instanceCreationExpression(Keyword.NEW, typeName("List"), "from", target)); return null; } if (isMethodInClass(node, "iterator", "java.util.Collection")) { replaceNode( node, instanceCreationExpression(Keyword.NEW, typeName("JavaIterator"), target)); return null; } if (isMethodInClass(node, "hasNext", "java.util.Iterator")) { replaceNode(node, propertyAccess(target, nameNode)); return null; } if (isMethodInClass(node, "containsAll", "java.util.Collection")) { replaceNode(node, methodInvocation("javaCollectionContainsAll", target, args.get(0))); return null; } if (isMethodInClass(node, "isEmpty", "java.util.Map")) { replaceNode(node, propertyAccess(target, nameNode)); return null; } if (isMethodInClass(node, "put", "java.util.Map")) { if (node.getParent() instanceof ExpressionStatement) { IndexExpression indexExpression = indexExpression(target, args.get(0)); AssignmentExpression assignment = assignmentExpression( indexExpression, TokenType.EQ, args.get(1)); replaceNode(node, assignment); } else { replaceNode(node, methodInvocation("javaMapPut", target, args.get(0), args.get(1))); } return null; } if (isMethodInClass(node, "entrySet", "java.util.Map")) { replaceNode(node, methodInvocation("getMapEntrySet", target)); return null; } if (isMethodInClass(node, "values", "java.util.Map")) { replaceNode(node, propertyAccess(target, nameNode)); return null; } if (isMethodInClass(node, "keySet", "java.util.Map")) { nameNode.setToken(token("keys")); replaceNode(node, methodInvocation(propertyAccess(target, nameNode), "toSet")); return null; } if (isMethodInClass2(node, "remove(int)", "java.util.List")) { nameNode.setToken(TokenFactory.token("removeAt")); return null; } if (isMethodInClass2(node, "add(int,java.lang.Object)", "java.util.List")) { nameNode.setToken(TokenFactory.token("insert")); return null; } if (isMethodInClass(node, "set", "java.util.List")) { replaceNode(node, methodInvocation("javaListSet", target, args.get(0), args.get(1))); return null; } if (isMethodInClass(node, "putAll", "java.util.Map")) { nameNode.setToken(TokenFactory.token("addAll")); return null; } if (isMethodInClass(node, "addAll", "java.util.Collections")) { replaceNode(node, methodInvocation(args.get(0), "addAll", args.get(1))); return null; } if (isMethodInClass(node, "unmodifiableList", "java.util.Collections")) { replaceNode( node, instanceCreationExpression(Keyword.NEW, typeName("UnmodifiableListView"), args.get(0))); return null; } if (isMethodInClass(node, "sort", "java.util.Arrays")) { if (args.size() == 1) { replaceNode(node, methodInvocation(args.get(0), "sort")); } else { replaceNode(node, methodInvocation(args.get(0), "sort", args.get(1))); } return null; } if (isMethodInClass(node, "hashCode", "java.util.Arrays")) { nameNode.setToken(token("makeHashCode")); return null; } if (isMethodInClass(node, "sort", "java.util.Collections")) { replaceNode(node, methodInvocation(args.get(0), "sort", args.get(1))); return null; } if (isMethodInClass(node, "add", "org.apache.commons.lang3.ArrayUtils") && args.size() == 3) { nameNode.setToken(TokenFactory.token("addAt")); return null; } if (isMethodInClass(node, "noneOf", "java.util.EnumSet")) { replaceNode(node, instanceCreationExpression(Keyword.NEW, typeName("HashSet"))); return null; } return null; } @Override public Void visitSimpleIdentifier(SimpleIdentifier node) { Object binding = context.getNodeBinding(node); if (JavaUtils.isTypeNamed(binding, "java.util.Arrays")) { replaceNode(node, identifier("JavaArrays")); return null; } return super.visitSimpleIdentifier(node); } @Override public Void visitTypeName(TypeName node) { super.visitTypeName(node); ITypeBinding binding = context.getNodeTypeBinding(node); if (node.getName() instanceof SimpleIdentifier) { SimpleIdentifier nameNode = (SimpleIdentifier) node.getName(); String name = nameNode.getName(); if (JavaUtils.isTypeNamed(binding, "java.util.Collection")) { nameNode.setToken(token("Iterable")); return null; } if (JavaUtils.isTypeNamed(binding, "java.util.ArrayList")) { nameNode.setToken(token("List")); return null; } if (JavaUtils.isTypeNamed(binding, "java.util.LinkedList")) { nameNode.setToken(token("Queue")); return null; } if ("EnumSet".equals(name)) { nameNode.setToken(token("HashSet")); return null; } if ("HashSet".equals(name)) { nameNode.setToken(token("HashSet")); return null; } if ("HashMap".equals(name)) { nameNode.setToken(token("HashMap")); return null; } if (JavaUtils.isTypeNamed(binding, "java.util.Map.Entry")) { nameNode.setToken(token("MapEntry")); return null; } if (JavaUtils.isTypeNamed(binding, "java.util.Iterator")) { nameNode.setToken(token("JavaIterator")); return null; } } return null; } }); } }