Skip to content

Commit

Permalink
Adds implicit super() calls to the converted tree. This is more consi…
Browse files Browse the repository at this point in the history
…stent with the Javac tree.

	Change on 2016/12/22 by kstanger <kstanger@google.com>

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=142783050
  • Loading branch information
kstanger authored and tomball committed Dec 28, 2016
1 parent f740d2f commit 5441c0a
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 72 deletions.
Expand Up @@ -524,8 +524,6 @@ private TreeNode convertBinary(JCTree.JCBinary node) {
return newNode; return newNode;
} }




private TreeNode convertBlock(JCTree.JCBlock node) { private TreeNode convertBlock(JCTree.JCBlock node) {
Block newNode = new Block(); Block newNode = new Block();
for (StatementTree stmt : node.getStatements()) { for (StatementTree stmt : node.getStatements()) {
Expand Down Expand Up @@ -673,21 +671,6 @@ private TreeNode convertEnum(JCTree.JCClassDecl node) {
} else { } else {
newNode.addBodyDeclaration((BodyDeclaration) var); newNode.addBodyDeclaration((BodyDeclaration) var);
} }
} else if (bodyDecl.getKind() == Kind.METHOD) {
MethodDeclaration method = (MethodDeclaration) convert((JCTree.JCMethodDecl) bodyDecl);
if (ElementUtil.isConstructor(method.getExecutableElement())
&& !method.getBody().getStatements().isEmpty()){
// Remove bogus "super()" call from constructors, so InitializationNormalizer
// adds the correct super call that includes the ordinal and name arguments.
Statement stmt = method.getBody().getStatements().get(0);
if (stmt.getKind() == TreeNode.Kind.SUPER_CONSTRUCTOR_INVOCATION) {
SuperConstructorInvocation call = (SuperConstructorInvocation) stmt;
if (call.getArguments().isEmpty()) {
method.getBody().getStatements().remove(0);
}
}
}
newNode.addBodyDeclaration(method);
} else { } else {
newNode.addBodyDeclaration((BodyDeclaration) convert(bodyDecl)); newNode.addBodyDeclaration((BodyDeclaration) convert(bodyDecl));
} }
Expand Down
Expand Up @@ -85,6 +85,11 @@ public Element asElement(TypeMirror t) {


@Override @Override
public TypeMirror asMemberOf(DeclaredType containing, Element element) { public TypeMirror asMemberOf(DeclaredType containing, Element element) {
return asMemberOfInternal(containing, element);
}

// Static version of the above for internal use.
static TypeMirror asMemberOfInternal(DeclaredType containing, Element element) {
ITypeBinding c = BindingConverter.unwrapTypeMirrorIntoTypeBinding(containing); ITypeBinding c = BindingConverter.unwrapTypeMirrorIntoTypeBinding(containing);
if (ElementUtil.isExecutableElement(element)) { if (ElementUtil.isExecutableElement(element)) {
IMethodBinding e = BindingConverter.unwrapExecutableElement((ExecutableElement) element); IMethodBinding e = BindingConverter.unwrapExecutableElement((ExecutableElement) element);
Expand Down
Expand Up @@ -14,6 +14,7 @@


package com.google.devtools.j2objc.jdt; package com.google.devtools.j2objc.jdt;


import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.devtools.j2objc.ast.AbstractTypeDeclaration; import com.google.devtools.j2objc.ast.AbstractTypeDeclaration;
import com.google.devtools.j2objc.ast.AnnotatableType; import com.google.devtools.j2objc.ast.AnnotatableType;
Expand Down Expand Up @@ -117,16 +118,21 @@
import com.google.devtools.j2objc.types.ExecutablePair; import com.google.devtools.j2objc.types.ExecutablePair;
import com.google.devtools.j2objc.types.GeneratedVariableElement; import com.google.devtools.j2objc.types.GeneratedVariableElement;
import com.google.devtools.j2objc.util.BindingUtil; import com.google.devtools.j2objc.util.BindingUtil;
import com.google.devtools.j2objc.util.ElementUtil;
import com.google.devtools.j2objc.util.TranslationEnvironment; import com.google.devtools.j2objc.util.TranslationEnvironment;
import com.google.devtools.j2objc.util.TypeUtil;
import com.google.j2objc.annotations.Property; import com.google.j2objc.annotations.Property;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement; import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement; import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.IMethodBinding;
Expand Down Expand Up @@ -408,6 +414,7 @@ private static TreeNode convertAbstractTypeDeclaration(
MethodDeclaration defaultConstructor = MethodDeclaration defaultConstructor =
new MethodDeclaration(BindingConverter.getExecutableElement(method)) new MethodDeclaration(BindingConverter.getExecutableElement(method))
.setBody(new Block()); .setBody(new Block());
addImplicitSuperCall(defaultConstructor);
newNode.addBodyDeclaration(0, defaultConstructor); newNode.addBodyDeclaration(0, defaultConstructor);
break; break;
} }
Expand Down Expand Up @@ -922,12 +929,14 @@ private static TreeNode convertMethodDeclaration(
for (Object param : node.parameters()) { for (Object param : node.parameters()) {
newNode.addParameter((SingleVariableDeclaration) TreeConverter.convert(param)); newNode.addParameter((SingleVariableDeclaration) TreeConverter.convert(param));
} }
return newNode newNode
.setName((SimpleName) TreeConverter.convert(node.getName())) .setName((SimpleName) TreeConverter.convert(node.getName()))
.setIsConstructor(node.isConstructor()) .setIsConstructor(node.isConstructor())
.setReturnType((Type) TreeConverter.convert(node.getReturnType2())) .setReturnType((Type) TreeConverter.convert(node.getReturnType2()))
.setExecutableElement(BindingConverter.getExecutableElement(node.resolveBinding())) .setExecutableElement(BindingConverter.getExecutableElement(node.resolveBinding()))
.setBody((Block) TreeConverter.convert(node.getBody())); .setBody((Block) TreeConverter.convert(node.getBody()));
maybeAddImplicitSuperCall(newNode);
return newNode;
} }


private static TreeNode convertMethodInvocation(org.eclipse.jdt.core.dom.MethodInvocation node) { private static TreeNode convertMethodInvocation(org.eclipse.jdt.core.dom.MethodInvocation node) {
Expand Down Expand Up @@ -1307,6 +1316,70 @@ private static TreeNode convertWhileStatement(org.eclipse.jdt.core.dom.WhileStat
.setBody((Statement) convert(node.getBody())); .setBody((Statement) convert(node.getBody()));
} }


private static void maybeAddImplicitSuperCall(MethodDeclaration node) {
if (needsImplicitSuperCall(node)) {
addImplicitSuperCall(node);
}
}

private static boolean needsImplicitSuperCall(MethodDeclaration node) {
ExecutableElement method = node.getExecutableElement();
if (!ElementUtil.isConstructor(method)) {
return false;
}
TypeMirror superType = ElementUtil.getDeclaringClass(method).getSuperclass();
if (TypeUtil.isNone(superType)) { // java.lang.Object supertype is null.
return false;
}
List<Statement> stmts = node.getBody().getStatements();
if (stmts.isEmpty()) {
return true;
}
Statement firstStmt = stmts.get(0);
return !(firstStmt instanceof SuperConstructorInvocation
|| firstStmt instanceof ConstructorInvocation);
}

private static void addImplicitSuperCall(MethodDeclaration node) {
ExecutableElement method = node.getExecutableElement();
DeclaredType superType = (DeclaredType) ElementUtil.getDeclaringClass(method).getSuperclass();
TypeElement superClass = TypeUtil.asTypeElement(superType);
ExecutableElement superConstructor = findDefaultConstructorElement(superClass);
node.getBody().addStatement(0, new SuperConstructorInvocation(new ExecutablePair(
superConstructor,
(ExecutableType) JdtTypes.asMemberOfInternal(superType, superConstructor))));
}

private static ExecutableElement findDefaultConstructorElement(TypeElement type) {
if (ElementUtil.getQualifiedName(type).equals("java.lang.Enum")) {
// Enums are a special case where instead of a default no-param constructor it has a single
// two param constructor that accepts the implicit name and ordinal values.
ExecutableElement enumConstructor =
Iterables.getFirst(ElementUtil.getConstructors(type), null);
assert enumConstructor != null && enumConstructor.getParameters().size() == 2;
return enumConstructor;
}
ExecutableElement result = null;
for (ExecutableElement c : ElementUtil.getConstructors(type)) {
// Search for a non-varargs match.
if (c.getParameters().isEmpty()) {
return c;
// Search for a varargs match. Choose the most specific. (JLS 15.12.2.5)
} else if (c.isVarArgs() && c.getParameters().size() == 1
&& (result == null || isAssignable(
c.getParameters().get(0).asType(), result.getParameters().get(0).asType()))) {
result = c;
}
}
assert result != null : "Couldn't find default constructor for " + type;
return result;
}

private static boolean isAssignable(TypeMirror t1, TypeMirror t2) {
return BindingConverter.unwrapTypeMirrorIntoTypeBinding(t1).isAssignmentCompatible(
BindingConverter.unwrapTypeMirrorIntoTypeBinding(t2));
}

// Helper class for convertInfixExpression(). // Helper class for convertInfixExpression().
private static class StackState { private static class StackState {
private final org.eclipse.jdt.core.dom.InfixExpression expression; private final org.eclipse.jdt.core.dom.InfixExpression expression;
Expand Down
Expand Up @@ -240,21 +240,21 @@ public void endVisit(SuperMethodInvocation node) {
public void endVisit(SuperConstructorInvocation node) { public void endVisit(SuperConstructorInvocation node) {
ExecutableElement element = node.getExecutableElement(); ExecutableElement element = node.getExecutableElement();
AbstractTypeDeclaration typeDecl = TreeUtil.getEnclosingType(node); AbstractTypeDeclaration typeDecl = TreeUtil.getEnclosingType(node);
TypeElement superType = ElementUtil.getSuperclass(typeDecl.getTypeElement()); TypeElement type = typeDecl.getTypeElement();
FunctionElement funcElement = newFunctionElement(element); FunctionElement funcElement = newFunctionElement(element);
FunctionInvocation invocation = new FunctionInvocation(funcElement, typeUtil.getVoid()); FunctionInvocation invocation = new FunctionInvocation(funcElement, typeUtil.getVoid());
List<Expression> args = invocation.getArguments(); List<Expression> args = invocation.getArguments();
args.add(new ThisExpression(ElementUtil.getDeclaringClass(element).asType())); args.add(new ThisExpression(ElementUtil.getDeclaringClass(element).asType()));
if (typeDecl instanceof TypeDeclaration) { if (typeDecl instanceof TypeDeclaration) {
TypeDeclaration typeDeclaration = (TypeDeclaration) typeDecl; TypeDeclaration typeDeclaration = (TypeDeclaration) typeDecl;
if (captureInfo.needsOuterParam(superType)) { if (captureInfo.needsOuterParam(ElementUtil.getSuperclass(type))) {
Expression outerArg = TreeUtil.remove(node.getExpression()); Expression outerArg = TreeUtil.remove(node.getExpression());
args.add(outerArg != null ? outerArg : typeDeclaration.getSuperOuter().copy()); args.add(outerArg != null ? outerArg : typeDeclaration.getSuperOuter().copy());
} }
TreeUtil.moveList(typeDeclaration.getSuperCaptureArgs(), args); TreeUtil.moveList(typeDeclaration.getSuperCaptureArgs(), args);
} }
TreeUtil.moveList(node.getArguments(), args); TreeUtil.moveList(node.getArguments(), args);
if (ElementUtil.isEnum(superType)) { if (ElementUtil.isEnum(type)) {
for (VariableElement param : captureInfo.getImplicitEnumParams()) { for (VariableElement param : captureInfo.getImplicitEnumParams()) {
args.add(new SimpleName(param)); args.add(new SimpleName(param));
} }
Expand Down
Expand Up @@ -16,7 +16,6 @@


package com.google.devtools.j2objc.translate; package com.google.devtools.j2objc.translate;


import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.devtools.j2objc.ast.AbstractTypeDeclaration; import com.google.devtools.j2objc.ast.AbstractTypeDeclaration;
import com.google.devtools.j2objc.ast.AnnotationTypeDeclaration; import com.google.devtools.j2objc.ast.AnnotationTypeDeclaration;
Expand All @@ -37,18 +36,13 @@
import com.google.devtools.j2objc.ast.TypeDeclaration; import com.google.devtools.j2objc.ast.TypeDeclaration;
import com.google.devtools.j2objc.ast.UnitTreeVisitor; import com.google.devtools.j2objc.ast.UnitTreeVisitor;
import com.google.devtools.j2objc.ast.VariableDeclarationFragment; import com.google.devtools.j2objc.ast.VariableDeclarationFragment;
import com.google.devtools.j2objc.types.ExecutablePair;
import com.google.devtools.j2objc.util.CaptureInfo; import com.google.devtools.j2objc.util.CaptureInfo;
import com.google.devtools.j2objc.util.ElementUtil; import com.google.devtools.j2objc.util.ElementUtil;
import com.google.devtools.j2objc.util.TypeUtil; import com.google.devtools.j2objc.util.TypeUtil;
import com.google.devtools.j2objc.util.UnicodeUtils; import com.google.devtools.j2objc.util.UnicodeUtils;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.Modifier;


/** /**
Expand Down Expand Up @@ -179,14 +173,11 @@ private List<Statement> getInitLocation(MethodDeclaration node) {
if (!stmts.isEmpty() && stmts.get(0) instanceof SuperConstructorInvocation) { if (!stmts.isEmpty() && stmts.get(0) instanceof SuperConstructorInvocation) {
return stmts.subList(0, 1); return stmts.subList(0, 1);
} }
TypeMirror superType = // java.lang.Object supertype is null. All other types should have a super() call.
ElementUtil.getDeclaringClass(node.getExecutableElement()).getSuperclass(); assert TypeUtil.isNone(
if (TypeUtil.isNone(superType)) { // java.lang.Object supertype is null. ElementUtil.getDeclaringClass(node.getExecutableElement()).getSuperclass())
return stmts.subList(0, 0); : "Constructor didn't have a super() call.";
} return stmts.subList(0, 0);
// If there isn't a super invocation, add one (like all Java compilers do).
stmts.add(0, createDefaultSuperCall((DeclaredType) superType));
return stmts.subList(0, 1);
} }


private void addCaptureAssignments(MethodDeclaration constructor, TypeElement type) { private void addCaptureAssignments(MethodDeclaration constructor, TypeElement type) {
Expand All @@ -199,43 +190,6 @@ private void addCaptureAssignments(MethodDeclaration constructor, TypeElement ty
} }
} }


private SuperConstructorInvocation createDefaultSuperCall(DeclaredType type) {
TypeElement typeElem = TypeUtil.asTypeElement(type);
if (ElementUtil.getQualifiedName(typeElem).equals("java.lang.Enum")) {
// Enums are a special case where instead of a default no-param constructor it has a single
// two param constructor that accepts the implicit name and ordinal values.
ExecutableElement enumConstructor =
Iterables.getFirst(ElementUtil.getConstructors(typeElem), null);
assert enumConstructor != null && enumConstructor.getParameters().size() == 2;
SuperConstructorInvocation superCall = new SuperConstructorInvocation(
new ExecutablePair(enumConstructor, typeUtil.asMemberOf(type, enumConstructor)));
for (VariableElement param : captureInfo.getImplicitEnumParams()) {
superCall.addArgument(new SimpleName(param));
}
return superCall;
}
ExecutableElement defaultConstructor = findDefaultConstructorElement(typeElem);
return new SuperConstructorInvocation(new ExecutablePair(
defaultConstructor, typeUtil.asMemberOf(type, defaultConstructor)));
}

private ExecutableElement findDefaultConstructorElement(TypeElement type) {
ExecutableElement result = null;
for (ExecutableElement c : ElementUtil.getConstructors(type)) {
// Search for a non-varargs match.
if (c.getParameters().isEmpty()) {
return c;
// Search for a varargs match. Choose the most specific. (JLS 15.12.2.5)
} else if (c.isVarArgs() && c.getParameters().size() == 1
&& (result == null || typeUtil.isAssignable(
c.getParameters().get(0).asType(), result.getParameters().get(0).asType()))) {
result = c;
}
}
assert result != null : "Couldn't find default constructor for " + type;
return result;
}

/** /**
* Returns true if this is a constructor that doesn't call "this(...)". This constructors are * Returns true if this is a constructor that doesn't call "this(...)". This constructors are
* skipped so initializers aren't run more than once per instance creation. * skipped so initializers aren't run more than once per instance creation.
Expand Down
Expand Up @@ -31,6 +31,7 @@
import com.google.devtools.j2objc.ast.ReturnStatement; import com.google.devtools.j2objc.ast.ReturnStatement;
import com.google.devtools.j2objc.ast.SimpleName; import com.google.devtools.j2objc.ast.SimpleName;
import com.google.devtools.j2objc.ast.SingleVariableDeclaration; import com.google.devtools.j2objc.ast.SingleVariableDeclaration;
import com.google.devtools.j2objc.ast.SuperConstructorInvocation;
import com.google.devtools.j2objc.ast.SuperMethodInvocation; import com.google.devtools.j2objc.ast.SuperMethodInvocation;
import com.google.devtools.j2objc.ast.SuperMethodReference; import com.google.devtools.j2objc.ast.SuperMethodReference;
import com.google.devtools.j2objc.ast.TreeNode; import com.google.devtools.j2objc.ast.TreeNode;
Expand Down Expand Up @@ -133,6 +134,8 @@ private void createCreation() {
// Add the implicit constructor to call. // Add the implicit constructor to call.
MethodDeclaration constructorDecl = new MethodDeclaration(constructorElement); MethodDeclaration constructorDecl = new MethodDeclaration(constructorElement);
constructorDecl.setBody(new Block()); constructorDecl.setBody(new Block());
constructorDecl.getBody().addStatement(new SuperConstructorInvocation(
new ExecutablePair(getObjectConstructor())));
typeDecl.addBodyDeclaration(constructorDecl); typeDecl.addBodyDeclaration(constructorDecl);


creation = new ClassInstanceCreation( creation = new ClassInstanceCreation(
Expand Down Expand Up @@ -313,4 +316,13 @@ private static String getParamName(int i) {
} }
return sb.reverse().toString(); return sb.reverse().toString();
} }

private ExecutableElement getObjectConstructor() {
for (ExecutableElement constructor : ElementUtil.getConstructors(typeUtil.getJavaObject())) {
if (constructor.getParameters().isEmpty()) {
return constructor;
}
}
throw new AssertionError("Can't find constructor for java.lang.Object.");
}
} }

0 comments on commit 5441c0a

Please sign in to comment.