Skip to content

Commit

Permalink
Moves captured variables to the beginning of the argument list instea…
Browse files Browse the repository at this point in the history
…d of the end so that they don't conflict with vararg parameters.

	Change on 2015/04/02 by kstanger <kstanger@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=90152921
  • Loading branch information
kstanger committed Apr 9, 2015
1 parent 942c35c commit 5cae247
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 54 deletions.
Expand Up @@ -25,6 +25,7 @@
import com.google.devtools.j2objc.ast.CompilationUnit; import com.google.devtools.j2objc.ast.CompilationUnit;
import com.google.devtools.j2objc.ast.ConstructorInvocation; import com.google.devtools.j2objc.ast.ConstructorInvocation;
import com.google.devtools.j2objc.ast.EnumDeclaration; import com.google.devtools.j2objc.ast.EnumDeclaration;
import com.google.devtools.j2objc.ast.Expression;
import com.google.devtools.j2objc.ast.ExpressionStatement; import com.google.devtools.j2objc.ast.ExpressionStatement;
import com.google.devtools.j2objc.ast.FieldDeclaration; import com.google.devtools.j2objc.ast.FieldDeclaration;
import com.google.devtools.j2objc.ast.MethodDeclaration; import com.google.devtools.j2objc.ast.MethodDeclaration;
Expand Down Expand Up @@ -167,39 +168,36 @@ private void updateConstructors(AbstractTypeDeclaration node) {
} }
} }


private GeneratedVariableBinding addParameter(
MethodDeclaration constructor, ITypeBinding paramType, String name, int idx) {
GeneratedMethodBinding constructorBinding =
new GeneratedMethodBinding(constructor.getMethodBinding().getMethodDeclaration());
constructor.setMethodBinding(constructorBinding);
GeneratedVariableBinding paramBinding = new GeneratedVariableBinding(
name, Modifier.FINAL, paramType, false, true, constructorBinding.getDeclaringClass(),
constructorBinding);
SingleVariableDeclaration paramNode = new SingleVariableDeclaration(paramBinding);
if (idx == -1) {
constructor.getParameters().add(paramNode);
constructorBinding.addParameter(paramType);
} else {
constructor.getParameters().add(idx, paramNode);
constructorBinding.addParameter(idx, paramType);
}
return paramBinding;
}

protected void addOuterParameters( protected void addOuterParameters(
AbstractTypeDeclaration typeNode, MethodDeclaration constructor) { AbstractTypeDeclaration typeNode, MethodDeclaration constructor) {
ITypeBinding type = typeNode.getTypeBinding(); ITypeBinding type = typeNode.getTypeBinding();
ITypeBinding outerType = type.getDeclaringClass(); ITypeBinding outerType = type.getDeclaringClass();
IVariableBinding outerParamBinding = null; IVariableBinding outerParamBinding = null;

GeneratedMethodBinding constructorBinding =
new GeneratedMethodBinding(constructor.getMethodBinding().getMethodDeclaration());
constructor.setMethodBinding(constructorBinding);

// Adds the outer and captured parameters to the declaration.
List<SingleVariableDeclaration> captureDecls = constructor.getParameters().subList(0, 0);
List<ITypeBinding> captureTypes = constructorBinding.getParameters().subList(0, 0);
if (OuterReferenceResolver.needsOuterParam(type)) { if (OuterReferenceResolver.needsOuterParam(type)) {
outerParamBinding = addParameter(constructor, outerType, "outer$", 0); GeneratedVariableBinding paramBinding = new GeneratedVariableBinding(
"outer$", Modifier.FINAL, outerType, false, true, type, constructorBinding);
captureDecls.add(new SingleVariableDeclaration(paramBinding));
captureTypes.add(outerType);
outerParamBinding = paramBinding;
} }
List<IVariableBinding> innerFields = OuterReferenceResolver.getInnerFields(type); List<IVariableBinding> innerFields = OuterReferenceResolver.getInnerFields(type);
List<IVariableBinding> captureParams = Lists.newArrayListWithCapacity(innerFields.size()); List<IVariableBinding> captureParams = Lists.newArrayListWithCapacity(innerFields.size());
int captureCount = 0; int captureCount = 0;
for (IVariableBinding innerField : innerFields) { for (IVariableBinding innerField : innerFields) {
captureParams.add(addParameter( GeneratedVariableBinding paramBinding = new GeneratedVariableBinding(
constructor, innerField.getType(), "capture$" + captureCount++, -1)); "capture$" + captureCount++, Modifier.FINAL, innerField.getType(), false, true, type,
constructorBinding);
captureDecls.add(new SingleVariableDeclaration(paramBinding));
captureTypes.add(innerField.getType());
captureParams.add(paramBinding);
} }


ConstructorInvocation thisCall = null; ConstructorInvocation thisCall = null;
Expand All @@ -220,13 +218,15 @@ protected void addOuterParameters(
GeneratedMethodBinding newThisBinding = GeneratedMethodBinding newThisBinding =
new GeneratedMethodBinding(thisCall.getMethodBinding().getMethodDeclaration()); new GeneratedMethodBinding(thisCall.getMethodBinding().getMethodDeclaration());
thisCall.setMethodBinding(newThisBinding); thisCall.setMethodBinding(newThisBinding);
List<Expression> args = thisCall.getArguments().subList(0, 0);
List<ITypeBinding> params = newThisBinding.getParameters().subList(0, 0);
if (outerParamBinding != null) { if (outerParamBinding != null) {
thisCall.getArguments().add(0, new SimpleName(outerParamBinding)); args.add(new SimpleName(outerParamBinding));
newThisBinding.addParameter(0, outerParamBinding.getType()); params.add(outerParamBinding.getType());
} }
for (IVariableBinding captureParam : captureParams) { for (IVariableBinding captureParam : captureParams) {
thisCall.getArguments().add(new SimpleName(captureParam)); args.add(new SimpleName(captureParam));
newThisBinding.addParameter(captureParam.getType()); params.add(captureParam.getType());
} }
} else { } else {
ITypeBinding superType = type.getSuperclass().getTypeDeclaration(); ITypeBinding superType = type.getSuperclass().getTypeDeclaration();
Expand Down
Expand Up @@ -77,11 +77,17 @@ public boolean visit(ClassInstanceCreation node) {
GeneratedMethodBinding binding = GeneratedMethodBinding binding =
new GeneratedMethodBinding(node.getMethodBinding().getMethodDeclaration()); new GeneratedMethodBinding(node.getMethodBinding().getMethodDeclaration());
node.setMethodBinding(binding); node.setMethodBinding(binding);
addOuterArg(node, binding, declaringClass);
List<Expression> captureArgs = node.getArguments().subList(0, 0);
List<ITypeBinding> captureParams = binding.getParameters().subList(0, 0);
if (OuterReferenceResolver.needsOuterParam(newType)) {
captureArgs.add(getOuterArg(node, declaringClass));
captureParams.add(declaringClass);
}


for (IVariableBinding capturedVar : getCapturedVariables(node)) { for (IVariableBinding capturedVar : getCapturedVariables(node)) {
node.getArguments().add(new SimpleName(capturedVar)); captureArgs.add(new SimpleName(capturedVar));
binding.addParameter(capturedVar.getType()); captureParams.add(capturedVar.getType());
} }


assert binding.isVarargs() || node.getArguments().size() == binding.getParameterTypes().length; assert binding.isVarargs() || node.getArguments().size() == binding.getParameterTypes().length;
Expand All @@ -98,28 +104,17 @@ private List<IVariableBinding> getCapturedVariables(ClassInstanceCreation node)
return OuterReferenceResolver.getCapturedVars(newType); return OuterReferenceResolver.getCapturedVars(newType);
} }


private void addOuterArg( private Expression getOuterArg(ClassInstanceCreation node, ITypeBinding declaringClass) {
ClassInstanceCreation node, GeneratedMethodBinding binding, ITypeBinding declaringClass) {
ITypeBinding type = node.getTypeBinding().getTypeDeclaration();
if (!OuterReferenceResolver.needsOuterParam(type)) {
return;
}

Expression outerExpr = node.getExpression(); Expression outerExpr = node.getExpression();
List<IVariableBinding> path = OuterReferenceResolver.getPath(node);
Expression outerArg = null;

if (outerExpr != null) { if (outerExpr != null) {
node.setExpression(null); node.setExpression(null);
outerArg = outerExpr; return outerExpr;
} else if (path != null) {
outerArg = Name.newName(fixPath(path));
} else {
outerArg = new ThisExpression(declaringClass);
} }

List<IVariableBinding> path = OuterReferenceResolver.getPath(node);
node.getArguments().add(0, outerArg); if (path != null) {
binding.addParameter(0, declaringClass); return Name.newName(fixPath(path));
}
return new ThisExpression(declaringClass);
} }


@Override @Override
Expand Down
Expand Up @@ -160,6 +160,10 @@ public void addParameters(IMethodBinding method) {
parameters.addAll(Arrays.asList(method.getParameterTypes())); parameters.addAll(Arrays.asList(method.getParameterTypes()));
} }


public List<ITypeBinding> getParameters() {
return parameters;
}

@Override @Override
public ITypeBinding getReturnType() { public ITypeBinding getReturnType() {
return returnType; return returnType;
Expand Down
Expand Up @@ -366,11 +366,11 @@ public void testTwoOutersInAnonymousSubClassOfInner() throws IOException {
+ "}", + "}",
"Test", "Test.m"); "Test", "Test.m");
assertTranslation(translation, assertTranslation(translation,
"new_Test_A_$1_initWithTest_A_withTest_B_withInt_withTest_B_(self, b, 1, b)"); "new_Test_A_$1_initWithTest_A_withTest_B_withTest_B_withInt_(self, b, b, 1)");
assertTranslatedLines(translation, assertTranslatedLines(translation,
"void Test_A_$1_initWithTest_A_withTest_B_withInt_withTest_B_(" "void Test_A_$1_initWithTest_A_withTest_B_withTest_B_withInt_("
+ "Test_A_$1 *self, Test_A *outer$, Test_B *superOuter$, jint arg$0, " + "Test_A_$1 *self, Test_A *outer$, Test_B *capture$0, Test_B *superOuter$, "
+ "Test_B *capture$0) {", + "jint arg$0) {",
" Test_A_$1_set_this$1_(self, outer$);", " Test_A_$1_set_this$1_(self, outer$);",
" Test_A_$1_set_val$b_(self, capture$0);", " Test_A_$1_set_val$b_(self, capture$0);",
" Test_B_Inner_initWithTest_B_withInt_(self, superOuter$, arg$0);", " Test_B_Inner_initWithTest_B_withInt_(self, superOuter$, arg$0);",
Expand Down
Expand Up @@ -771,11 +771,11 @@ public void testLocalClassWithCaptureVariables() throws IOException {
assertTranslation(translation, "new_Test_1Inner_initWithNSString_(s)"); assertTranslation(translation, "new_Test_1Inner_initWithNSString_(s)");
assertTranslatedLines(translation, assertTranslatedLines(translation,
"void Test_1Inner_initWithNSString_(Test_1Inner *self, NSString *capture$0) {", "void Test_1Inner_initWithNSString_(Test_1Inner *self, NSString *capture$0) {",
" Test_1Inner_initWithInt_withNSString_(self, 0, capture$0);", " Test_1Inner_initWithNSString_withInt_(self, capture$0, 0);",
"}"); "}");
assertTranslatedLines(translation, assertTranslatedLines(translation,
"void Test_1Inner_initWithInt_withNSString_(" "void Test_1Inner_initWithNSString_withInt_("
+ "Test_1Inner *self, jint i, NSString *capture$0) {", + "Test_1Inner *self, NSString *capture$0, jint i) {",
" Test_1Inner_set_val$s_(self, capture$0);", " Test_1Inner_set_val$s_(self, capture$0);",
" NSObject_init(self);", " NSObject_init(self);",
"}"); "}");
Expand All @@ -789,4 +789,16 @@ public void testWeakStaticClass() throws IOException {
assertErrorCount(0); assertErrorCount(0);
assertNotInTranslation(translation, "__weak"); assertNotInTranslation(translation, "__weak");
} }

public void testInnerClassWithVarargsAndCaptureVariables() throws IOException {
String translation = translateSourceFile(
"class Test { int test(final int i, Object o) { class Inner { Inner(Object... o) {} "
+ "int foo() { return i; } } return new Inner(o).foo(); } }", "Test", "Test.m");
assertTranslation(translation,
"new_Test_1Inner_initWithInt_withNSObjectArray_(i, "
+ "[IOSObjectArray arrayWithObjects:(id[]){ o } count:1 type:NSObject_class_()])");
assertTranslation(translation,
"void Test_1Inner_initWithInt_withNSObjectArray_("
+ "Test_1Inner *self, jint capture$0, IOSObjectArray *o)");
}
} }

0 comments on commit 5cae247

Please sign in to comment.