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

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

Issue 18129004: Simplify constructors translation, improve code style. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 6 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/ConstructorSemanticProcessor.java
diff --git a/editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/ConstructorSemanticProcessor.java b/editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/ConstructorSemanticProcessor.java
index 90e595028adb76baf8edc10c10805c412ba86a21..c56fa791f1396acf2c3590290b864896a296e278 100644
--- a/editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/ConstructorSemanticProcessor.java
+++ b/editor/util/plugins/com.google.dart.java2dart/src/com/google/dart/java2dart/processor/ConstructorSemanticProcessor.java
@@ -13,25 +13,106 @@
*/
package com.google.dart.java2dart.processor;
+import com.google.common.collect.Lists;
+import com.google.dart.engine.ast.Block;
import com.google.dart.engine.ast.BlockFunctionBody;
import com.google.dart.engine.ast.ClassDeclaration;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.ConstructorDeclaration;
import com.google.dart.engine.ast.ConstructorInitializer;
+import com.google.dart.engine.ast.EmptyFunctionBody;
+import com.google.dart.engine.ast.Expression;
+import com.google.dart.engine.ast.ExpressionStatement;
+import com.google.dart.engine.ast.FormalParameter;
+import com.google.dart.engine.ast.FunctionBody;
+import com.google.dart.engine.ast.MethodInvocation;
import com.google.dart.engine.ast.NodeList;
+import com.google.dart.engine.ast.RedirectingConstructorInvocation;
+import com.google.dart.engine.ast.Statement;
import com.google.dart.engine.ast.SuperConstructorInvocation;
import com.google.dart.engine.ast.visitor.GeneralizingASTVisitor;
import com.google.dart.java2dart.Context;
+import com.google.dart.java2dart.Context.ConstructorDescription;
-import java.util.ArrayList;
+import static com.google.dart.java2dart.util.ASTFactory.emptyFunctionBody;
+import static com.google.dart.java2dart.util.ASTFactory.identifier;
+import static com.google.dart.java2dart.util.ASTFactory.redirectingConstructorInvocation;
+import static com.google.dart.java2dart.util.ASTFactory.simpleFormalParameter;
+import static com.google.dart.java2dart.util.ASTFactory.typeName;
+
+import org.eclipse.jdt.core.dom.IMethodBinding;
+
+import java.util.List;
/**
- * Simplifies generated of Dart constructors.
+ * Simplifies generated Dart constructors.
* <ul>
- * <li>if exactly one constructor that just calls super, then remove it</li>
+ * <li>If exactly one constructor that is default and just calls super, then remove it.</li>
+ * <li>If constructor has block body with no statements, then removes the body.</li>
+ * <li>If constructor has redirection marker invocation and no other statements, then replace the
+ * marker with the actual redirecting constructor invocation and removes the body.</li>
+ * <li>If constructor is an enum constructor with redirecting constructor invocation, then make its
+ * "name" and "ordinal" field formal initializing parameters the normal formal parameters and pass
+ * them into the redirecting constructor invocation.</li>
* </ul>
*/
public class ConstructorSemanticProcessor extends SemanticProcessor {
+
+ /**
+ * @return {@code true} if the given {@link ConstructorDeclaration} has no or empty body.
+ */
+ private static boolean hasEmptyBody(ConstructorDeclaration constructor) {
+ FunctionBody body = constructor.getBody();
+ // no body at all
+ if (body == null) {
+ return true;
+ }
+ if (body instanceof EmptyFunctionBody) {
+ return true;
+ }
+ // block body without statements
+ if (body instanceof BlockFunctionBody) {
+ Block block = ((BlockFunctionBody) body).getBlock();
+ return block.getStatements().isEmpty();
+ }
+ // expression body (probably never happens)
+ return false;
+ }
+
+ /**
+ * @return {@code true} if the constructor is default, has empty body, no initializers or one
+ * initializer calling default super constructor.
+ */
+ private static boolean hasNoParamAndOnlyCallsSuper(ConstructorDeclaration constructor) {
+ // no parameters
+ if (!constructor.getParameters().getParameters().isEmpty()) {
+ return false;
+ }
+ // empty body
+ if (!hasEmptyBody(constructor)) {
+ return false;
+ }
+ // at most one initializer allowed
+ NodeList<ConstructorInitializer> initializers = constructor.getInitializers();
+ if (initializers.size() == 0) {
+ return true;
+ }
+ if (initializers.size() > 1) {
+ return false;
+ }
+ // check that the only initializer is "super" constructor invocation
+ ConstructorInitializer initializer = initializers.get(0);
+ if (!(initializer instanceof SuperConstructorInvocation)) {
+ return false;
+ }
+ SuperConstructorInvocation superInitializer = (SuperConstructorInvocation) initializer;
+ if (!superInitializer.getArgumentList().getArguments().isEmpty()) {
+ return false;
+ }
+ // OK, there is only default "super" constructor invocation
+ return true;
+ }
+
public ConstructorSemanticProcessor(Context context) {
super(context);
}
@@ -39,62 +120,98 @@ public class ConstructorSemanticProcessor extends SemanticProcessor {
@Override
public void process(CompilationUnit unit) {
unit.accept(new GeneralizingASTVisitor<Void>() {
- ArrayList<ConstructorDeclaration> allConstructors = new ArrayList<ConstructorDeclaration>();
+ List<ConstructorDeclaration> allConstructors = Lists.newArrayList();;
@Override
public Void visitClassDeclaration(ClassDeclaration node) {
allConstructors.clear();
- Void result = super.visitClassDeclaration(node);
-
- // Remove constructor if only one with no param and all it does is call super
+ super.visitClassDeclaration(node);
+ // remove constructor if it is default and calls default super constructor
if (allConstructors.size() == 1) {
ConstructorDeclaration constructor = allConstructors.get(0);
if (hasNoParamAndOnlyCallsSuper(constructor)) {
node.getMembers().remove(allConstructors.remove(0));
}
}
-
- return result;
+ // done
+ return null;
}
@Override
public Void visitConstructorDeclaration(ConstructorDeclaration node) {
allConstructors.add(node);
- return super.visitConstructorDeclaration(node);
+ replaceThisInvocationMarkerWithRedirection(node);
+ // remove empty body
+ if (hasEmptyBody(node)) {
+ node.setBody(emptyFunctionBody());
+ }
+ // done
+ return null;
}
});
}
/**
- * Answer {@code true} if the constructor does not have any parameters and does not have any
- * statements other than a single call to the super constructor.
+ * If the given {@link ConstructorDeclaration} has only statement with marker for "this"
+ * constructor redirection, then replace it with the real redirection. This redirection will still
+ * have temporary name, will be replace with the real name during constructors rename step.
*/
- private boolean hasNoParamAndOnlyCallsSuper(ConstructorDeclaration constructor) {
- if (constructor.getParameters().getParameters().size() > 0) {
- return false;
+ private void replaceThisInvocationMarkerWithRedirection(ConstructorDeclaration node) {
+ // prepare statements
+ FunctionBody body = node.getBody();
+ if (!(body instanceof BlockFunctionBody)) {
+ return;
}
- if (!(constructor.getBody() instanceof BlockFunctionBody)) {
- return false;
+ Block block = ((BlockFunctionBody) body).getBlock();
+ NodeList<Statement> statements = block.getStatements();
+ // we support here only one statement
+ if (statements.size() != 1) {
+ return;
}
- BlockFunctionBody body = (BlockFunctionBody) constructor.getBody();
- if (body.getBlock().getStatements().size() > 0) {
- return false;
- }
- NodeList<ConstructorInitializer> initializers = constructor.getInitializers();
- if (initializers.size() == 0) {
- return true;
+ Statement statement = statements.get(0);
+ // the statement should be "thisConstructorRedirection" marker invocation
+ if (!(statement instanceof ExpressionStatement)) {
+ return;
}
- if (initializers.size() > 1) {
- return false;
+ Expression expression = ((ExpressionStatement) statement).getExpression();
+ if (!(expression instanceof MethodInvocation)) {
+ return;
}
- ConstructorInitializer initializer = initializers.get(0);
- if (!(initializer instanceof SuperConstructorInvocation)) {
- return false;
+ MethodInvocation methodInvocation = (MethodInvocation) expression;
+ if (methodInvocation.getTarget() != null
+ || !methodInvocation.getMethodName().getName().equals("thisConstructorRedirection")) {
+ return;
}
- SuperConstructorInvocation superInitializer = (SuperConstructorInvocation) initializer;
- if (superInitializer.getArgumentList().getArguments().size() > 0) {
- return false;
+ // add redirecting constructor invocation
+ RedirectingConstructorInvocation redirect = redirectingConstructorInvocation(
+ "thisConstructorRedirection",
+ methodInvocation.getArgumentList().getArguments());
+ node.getInitializers().add(redirect);
+ // remove body
+ node.setBody(emptyFunctionBody());
+ // record constructor invocation
+ IMethodBinding binding = (IMethodBinding) context.getNodeBinding(methodInvocation);
+ ConstructorDescription description = context.getConstructorDescription(binding);
+ description.redirectingInvocations.add(redirect);
+ // tweak enum constructor
+ if (description.isEnum) {
+ List<Expression> arguments = redirect.getArgumentList().getArguments();
+ updateRedirectingEnumConstructorParameters(node, arguments);
}
- return true;
+ }
+
+ /**
+ * When we translate Java enum constructor, we generate field formal parameters "name" and
+ * "ordinal". However if constructor is actually redirecting constructor, there parameters should
+ * not be field parameters, they should be normal ones and passed into
+ * {@link RedirectingConstructorInvocation}.
+ */
+ private void updateRedirectingEnumConstructorParameters(ConstructorDeclaration node,
+ List<Expression> arguments) {
+ NodeList<FormalParameter> parameters = node.getParameters().getParameters();
+ parameters.set(0, simpleFormalParameter(typeName("String"), identifier("name")));
+ parameters.set(1, simpleFormalParameter(typeName("int"), identifier("ordinal")));
+ arguments.add(0, identifier("name"));
+ arguments.add(1, identifier("ordinal"));
}
}

Powered by Google App Engine
This is Rietveld 408576698