Skip to content

Commit

Permalink
Create default method shims for all possible selectors of a default m…
Browse files Browse the repository at this point in the history
…ethod.

	Change on 2016/04/29 by kstanger <kstanger@google.com>

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=121144162
  • Loading branch information
kstanger authored and Keith Stanger committed May 2, 2016
1 parent d0e7f60 commit f900e31
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 60 deletions.
Expand Up @@ -29,8 +29,8 @@
import com.google.devtools.j2objc.ast.TreeVisitor; import com.google.devtools.j2objc.ast.TreeVisitor;
import com.google.devtools.j2objc.ast.TypeDeclaration; import com.google.devtools.j2objc.ast.TypeDeclaration;
import com.google.devtools.j2objc.types.FunctionBinding; import com.google.devtools.j2objc.types.FunctionBinding;
import com.google.devtools.j2objc.types.GeneratedMethodBinding;
import com.google.devtools.j2objc.types.GeneratedVariableBinding; import com.google.devtools.j2objc.types.GeneratedVariableBinding;
import com.google.devtools.j2objc.types.IOSMethodBinding;
import com.google.devtools.j2objc.util.BindingUtil; import com.google.devtools.j2objc.util.BindingUtil;
import com.google.devtools.j2objc.util.UnicodeUtils; import com.google.devtools.j2objc.util.UnicodeUtils;


Expand Down Expand Up @@ -135,48 +135,55 @@ private void addDefaultMethodShims(AbstractTypeDeclaration node) {
continue; continue;
} }


// Create the method binding and declaration. for (String selector : nameTable.getAllSelectors(method)) {
GeneratedMethodBinding binding = new GeneratedMethodBinding(method); node.getBodyDeclarations().add(createDefaultMethodShim(selector, method, type));

// Don't carry over the default method flag from the original binding.
binding.removeModifiers(Modifier.DEFAULT);
// Mark synthetic to avoid writing metadata.
binding.addModifiers(BindingUtil.ACC_SYNTHETIC);

binding.setDeclaringClass(type);
MethodDeclaration methodDecl = new MethodDeclaration(binding);
methodDecl.setHasDeclaration(false);

// The shim's only purpose is to call the default method implementation and returns it value
// if required.
String name = nameTable.getFullFunctionName(method);
FunctionBinding fb = new FunctionBinding(name, method.getReturnType(), type);
fb.addParameters(type);
fb.addParameters(method.getParameterTypes());
FunctionInvocation invocation = new FunctionInvocation(fb, method.getReturnType());

// All default method implementations require self as the first function call argument.
invocation.getArguments().add(new ThisExpression(type));

// For each parameter in the default method, assign a name, and use the name in both the
// method declaration and the function invocation.
for (int i = 0; i < method.getParameterTypes().length; i++) {
ITypeBinding paramType = method.getParameterTypes()[i];
String paramName = UnicodeUtils.format("arg%d", i);
GeneratedVariableBinding varBinding = new GeneratedVariableBinding(paramName, 0, paramType,
false, true, type, null);
methodDecl.getParameters().add(new SingleVariableDeclaration(varBinding));
invocation.getArguments().add(new SimpleName(varBinding));
} }
}
}


Statement stmt = BindingUtil.isVoid(method.getReturnType()) private MethodDeclaration createDefaultMethodShim(
? new ExpressionStatement(invocation) String selector, IMethodBinding method, ITypeBinding type) {
: new ReturnStatement(invocation); // Create the method binding and declaration.

IOSMethodBinding binding = IOSMethodBinding.newMappedMethod(selector, method);
Block block = new Block();
block.getStatements().add(stmt); // Don't carry over the default method flag from the original binding.
methodDecl.setBody(block); binding.removeModifiers(Modifier.DEFAULT);
node.getBodyDeclarations().add(methodDecl); // Mark synthetic to avoid writing metadata.
binding.addModifiers(BindingUtil.ACC_SYNTHETIC);

binding.setDeclaringClass(type);
MethodDeclaration methodDecl = new MethodDeclaration(binding);
methodDecl.setHasDeclaration(false);

// The shim's only purpose is to call the default method implementation and returns it value
// if required.
String name = nameTable.getFullFunctionName(method);
FunctionBinding fb = new FunctionBinding(name, method.getReturnType(), type);
fb.addParameters(type);
fb.addParameters(method.getParameterTypes());
FunctionInvocation invocation = new FunctionInvocation(fb, method.getReturnType());

// All default method implementations require self as the first function call argument.
invocation.getArguments().add(new ThisExpression(type));

// For each parameter in the default method, assign a name, and use the name in both the
// method declaration and the function invocation.
for (int i = 0; i < method.getParameterTypes().length; i++) {
ITypeBinding paramType = method.getParameterTypes()[i];
String paramName = UnicodeUtils.format("arg%d", i);
GeneratedVariableBinding varBinding = new GeneratedVariableBinding(paramName, 0, paramType,
false, true, type, null);
methodDecl.getParameters().add(new SingleVariableDeclaration(varBinding));
invocation.getArguments().add(new SimpleName(varBinding));
} }

Statement stmt = BindingUtil.isVoid(method.getReturnType())
? new ExpressionStatement(invocation)
: new ReturnStatement(invocation);

Block block = new Block();
block.getStatements().add(stmt);
methodDecl.setBody(block);
return methodDecl;
} }
} }
Expand Up @@ -524,12 +524,6 @@ private String addParamNames(IMethodBinding method, String name, char delim) {
} }


public String getMethodSelector(IMethodBinding method) { public String getMethodSelector(IMethodBinding method) {
if (method instanceof IOSMethodBinding) {
return ((IOSMethodBinding) method).getSelector();
}
if (method.isConstructor() || BindingUtil.isStatic(method)) {
return selectorForOriginalBinding(method);
}
return selectorForOriginalBinding(getOriginalMethodBindings(method).get(0)); return selectorForOriginalBinding(getOriginalMethodBindings(method).get(0));
} }


Expand All @@ -554,6 +548,9 @@ public String selectorForMethodName(IMethodBinding method, String name) {
} }


private String selectorForOriginalBinding(IMethodBinding method) { private String selectorForOriginalBinding(IMethodBinding method) {
if (method instanceof IOSMethodBinding) {
return ((IOSMethodBinding) method).getSelector();
}
String selector = getRenamedMethodName(method); String selector = getRenamedMethodName(method);
return selectorForMethodName( return selectorForMethodName(
method, selector != null ? selector : getMethodName(method)); method, selector != null ? selector : getMethodName(method));
Expand All @@ -565,20 +562,19 @@ private String selectorForOriginalBinding(IMethodBinding method) {
* not returned by getMethodSelector(). * not returned by getMethodSelector().
*/ */
public List<String> getExtraSelectors(IMethodBinding method) { public List<String> getExtraSelectors(IMethodBinding method) {
if (method instanceof IOSMethodBinding || method.isConstructor() List<String> allSelectors = getAllSelectors(method);
|| BindingUtil.isStatic(method)) { return allSelectors.subList(1, allSelectors.size());
return Collections.emptyList(); }
}
List<IMethodBinding> originalMethods = getOriginalMethodBindings(method); public List<String> getAllSelectors(IMethodBinding method) {
List<String> extraSelectors = new ArrayList<>(); List<String> selectors = new ArrayList<>();
String actualSelector = selectorForOriginalBinding(originalMethods.get(0)); for (IMethodBinding originalMethod : getOriginalMethodBindings(method)) {
for (int i = 1; i < originalMethods.size(); i++) { String selector = selectorForOriginalBinding(originalMethod);
String selector = selectorForOriginalBinding(originalMethods.get(i)); if (!selectors.contains(selector)) {
if (!selector.equals(actualSelector)) { selectors.add(selector);
extraSelectors.add(selector);
} }
} }
return extraSelectors; return selectors;
} }


/** /**
Expand Down Expand Up @@ -685,7 +681,8 @@ public static String getMethodNameFromAnnotation(IMethodBinding method) {
*/ */
private List<IMethodBinding> getOriginalMethodBindings(IMethodBinding method) { private List<IMethodBinding> getOriginalMethodBindings(IMethodBinding method) {
method = method.getMethodDeclaration(); method = method.getMethodDeclaration();
if (method.isConstructor() || BindingUtil.isStatic(method)) { if (method.isConstructor() || BindingUtil.isStatic(method)
|| method instanceof IOSMethodBinding) {
return Collections.singletonList(method); return Collections.singletonList(method);
} }
ITypeBinding declaringClass = method.getDeclaringClass(); ITypeBinding declaringClass = method.getDeclaringClass();
Expand Down
Expand Up @@ -402,4 +402,19 @@ public void testAccessingOuterType() throws IOException {
String impl = translateSourceFile(source, "Test", "Test.m"); String impl = translateSourceFile(source, "Test", "Test.m");
assertTranslatedLines(impl, "IOSClass *A_type(id<A> self) {", "return [self getClass];", "}"); assertTranslatedLines(impl, "IOSClass *A_type(id<A> self) {", "return [self getClass];", "}");
} }

public void testDefaultMethodWithMultipleSelectors() throws IOException {
addSourceFile("interface A <T> { void foo(T t); }", "A.java");
addSourceFile("interface B { void foo(String s); }", "B.java");
addSourceFile("interface C extends A<String>, B { default void foo(String s) {} }", "C.java");
addSourceFile("class D implements C {}", "D.java");
String headerC = translateSourceFile("C", "C.h");
String implD = translateSourceFile("D", "D.m");
assertTranslation(headerC, "- (void)fooWithId:(NSString *)s;");
assertTranslation(headerC, "- (void)fooWithNSString:(NSString *)s;");
assertTranslatedLines(implD,
"- (void)fooWithId:(NSString *)arg0 {", "C_fooWithNSString_(self, arg0);", "}");
assertTranslatedLines(implD,
"- (void)fooWithNSString:(NSString *)arg0 {", "C_fooWithNSString_(self, arg0);", "}");
}
} }

0 comments on commit f900e31

Please sign in to comment.