Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Unified Diff: editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/PropertySemanticProcessor.java

Issue 23769004: java2dart improvement - use field if getter/setter are trivial. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/PropertySemanticProcessor.java
diff --git a/editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/PropertySemanticProcessor.java b/editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/PropertySemanticProcessor.java
index d6d98090d43a2ee5e1b3bfcee3270da014a53c2a..0a21a09be4381f41d566113e58d5296bbdfb2f9a 100644
--- a/editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/PropertySemanticProcessor.java
+++ b/editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/PropertySemanticProcessor.java
@@ -14,33 +14,62 @@
package com.google.dart.java2dart.processor;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.dart.engine.ast.AssignmentExpression;
+import com.google.dart.engine.ast.BlockFunctionBody;
+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.Expression;
+import com.google.dart.engine.ast.ExpressionFunctionBody;
+import com.google.dart.engine.ast.ExpressionStatement;
import com.google.dart.engine.ast.FieldDeclaration;
import com.google.dart.engine.ast.FormalParameter;
import com.google.dart.engine.ast.MethodDeclaration;
import com.google.dart.engine.ast.MethodInvocation;
+import com.google.dart.engine.ast.PropertyAccess;
+import com.google.dart.engine.ast.SimpleFormalParameter;
import com.google.dart.engine.ast.SimpleIdentifier;
+import com.google.dart.engine.ast.Statement;
+import com.google.dart.engine.ast.ThisExpression;
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.Bindings;
import static com.google.dart.java2dart.util.ASTFactory.assignmentExpression;
import static com.google.dart.java2dart.util.ASTFactory.propertyAccess;
import static com.google.dart.java2dart.util.TokenFactory.token;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IMethodBinding;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* {@link SemanticProcessor} for converting <code>getX()</code> or <code>setX(x)</code> into getter
* or setter.
*/
public class PropertySemanticProcessor extends SemanticProcessor {
+ private static class FieldPropertyInfo {
+ final String name;
+ MethodDeclaration getter;
+ MethodDeclaration setter;
+ String getterField;
+ String setterField;
+
+ public FieldPropertyInfo(String name) {
+ this.name = name;
+ }
+ }
+
private static boolean hasPrefix(String name, String prefix) {
// should start with prefix
if (!name.startsWith(prefix)) {
@@ -151,5 +180,187 @@ public class PropertySemanticProcessor extends SemanticProcessor {
return super.visitMethodDeclaration(node);
}
});
+ // remember all overridden and overriding methods
+ final Set<IMethodBinding> ignoredMethods = Sets.newHashSet();
+ unit.accept(new GeneralizingASTVisitor<Void>() {
Brian Wilkerson 2013/09/04 16:48:59 It's a minor point, but if you're only invoking me
+ @Override
+ public Void visitMethodDeclaration(MethodDeclaration node) {
+ IMethodBinding binding = (IMethodBinding) context.getNodeBinding(node);
+ if (binding != null) {
+ IMethodBinding superBinding = Bindings.findOverriddenMethod(binding, true);
+ if (superBinding != null) {
+ ignoredMethods.add(binding);
+ ignoredMethods.add(superBinding);
+ }
+ }
+ return null;
+ }
+ });
+ // try to convert properties into fields
+ unit.accept(new GeneralizingASTVisitor<Void>() {
+ private final Map<String, FieldPropertyInfo> properties = Maps.newHashMap();
+
+ @Override
+ public Void visitClassDeclaration(ClassDeclaration node) {
+ properties.clear();
+ super.visitClassDeclaration(node);
+ // simplify field properties
+ for (FieldPropertyInfo property : properties.values()) {
+ MethodDeclaration getter = property.getter;
+ MethodDeclaration setter = property.setter;
+ // no getter or not field
+ if (getter == null || property.getterField == null) {
+ continue;
+ }
+ // setter is not field
+ if (setter != null && !StringUtils.equals(property.getterField, property.setterField)) {
+ continue;
+ }
+ // remove getter, update field
+ if (getter != null) {
+ ClassDeclaration clazz = (ClassDeclaration) getter.getParent();
+ List<ClassMember> members = clazz.getMembers();
+ members.remove(getter);
+ for (ClassMember member : members) {
+ if (member instanceof FieldDeclaration) {
+ FieldDeclaration fieldDeclaration = (FieldDeclaration) member;
+ List<VariableDeclaration> variables = fieldDeclaration.getFields().getVariables();
+ for (VariableDeclaration field : variables) {
+ SimpleIdentifier fieldName = field.getName();
+ if (fieldName.getName().equals(property.getterField)) {
+ context.renameIdentifier(fieldName, property.name);
+ // mark "final" is no writes
+ {
+ boolean readOnly = true;
+ List<SimpleIdentifier> references = context.getReferences(fieldName);
+ for (SimpleIdentifier reference : references) {
+ readOnly &= reference.inGetterContext();
Brian Wilkerson 2013/09/04 16:48:59 Given that getter and setter contexts are not mutu
+ }
+ if (readOnly) {
+ fieldDeclaration.getFields().setKeyword(token(Keyword.FINAL));
+ }
+ }
+ // now these are field references
+ {
+ IBinding fieldBinding = context.getNodeBinding(fieldName);
+ replaceMethodReferencesWithFieldBindings(getter, fieldBinding);
+ replaceMethodReferencesWithFieldBindings(setter, fieldBinding);
+ }
+ // done
+ break;
+ }
+ }
+ }
+ }
+ }
+ // remove setter
+ if (setter != null) {
+ ClassDeclaration clazz = (ClassDeclaration) setter.getParent();
+ List<ClassMember> members = clazz.getMembers();
+ members.remove(setter);
+ }
+ }
+ // done
+ return null;
+ }
+
+ @Override
+ public Void visitMethodDeclaration(MethodDeclaration node) {
+ // don't remove method if it overrides
+ {
+ IMethodBinding binding = (IMethodBinding) context.getNodeBinding(node);
+ if (binding == null) {
+ return null;
+ }
+ if (ignoredMethods.contains(binding)) {
+ return null;
+ }
+ }
+ // getter
+ if (node.isGetter()) {
+ String name = node.getName().getName();
+ FieldPropertyInfo property = getProperty(name);
+ property.getter = node;
+ if (node.getBody() instanceof ExpressionFunctionBody) {
+ ExpressionFunctionBody body = (ExpressionFunctionBody) node.getBody();
+ Expression expression = body.getExpression();
+ if (expression instanceof SimpleIdentifier) {
+ SimpleIdentifier identifier = (SimpleIdentifier) expression;
+ property.getterField = identifier.getName();
+ }
+ }
+ }
+ // setter
+ if (node.isSetter()) {
+ String name = node.getName().getName();
+ FieldPropertyInfo property = getProperty(name);
+ property.setter = node;
+ // block body
+ if (!(node.getBody() instanceof BlockFunctionBody)) {
+ return null;
+ }
+ // single statement
+ BlockFunctionBody body = (BlockFunctionBody) node.getBody();
+ List<Statement> statements = body.getBlock().getStatements();
+ if (statements.size() != 1) {
+ return null;
+ }
+ Statement statement = statements.get(0);
+ // prepare expression
+ if (!(statement instanceof ExpressionStatement)) {
+ return null;
+ }
+ Expression expression = ((ExpressionStatement) statement).getExpression();
+ // should be assignment
+ if (!(expression instanceof AssignmentExpression)) {
+ return null;
+ }
+ AssignmentExpression assignment = (AssignmentExpression) expression;
+ // simple assignment
+ if (assignment.getOperator().getType() != TokenType.EQ) {
+ return null;
+ }
+ // RHS should be just parameter name
+ Expression rhs = assignment.getRightHandSide();
+ if (!(rhs instanceof SimpleIdentifier)) {
+ return null;
+ }
+ SimpleIdentifier rhsName = (SimpleIdentifier) rhs;
+ String parameterName = ((SimpleFormalParameter) node.getParameters().getParameters().get(
+ 0)).getIdentifier().getName();
+ if (!rhsName.getName().equals(parameterName)) {
+ return null;
+ }
+ // LHS
+ Expression lhs = assignment.getLeftHandSide();
+ if (lhs instanceof PropertyAccess) {
+ PropertyAccess access = (PropertyAccess) lhs;
+ if (access.getTarget() instanceof ThisExpression) {
+ property.setterField = access.getPropertyName().getName();
+ }
+ }
+ }
+ return null;
+ }
+
+ private FieldPropertyInfo getProperty(String name) {
+ FieldPropertyInfo property = properties.get(name);
+ if (property == null) {
+ property = new FieldPropertyInfo(name);
+ properties.put(name, property);
+ }
+ return property;
+ }
+
+ private void replaceMethodReferencesWithFieldBindings(MethodDeclaration method,
+ IBinding fieldBinding) {
+ if (method == null) {
+ return;
+ }
+ for (SimpleIdentifier reference : context.getReferences(method.getName())) {
+ context.putReference(reference, fieldBinding, null);
+ }
+ }
+ });
}
}

Powered by Google App Engine
This is Rietveld 408576698