Skip to content

Commit

Permalink
Allows IOSMethodBinding to be created from a selector string instead …
Browse files Browse the repository at this point in the history
…of the more complex IOSMethod object.

	Change on 2015/02/12 by kstanger <kstanger@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=86203821
  • Loading branch information
kstanger committed Feb 25, 2015
1 parent e784b7b commit b30480f
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 112 deletions.
Expand Up @@ -14,7 +14,6 @@

package com.google.devtools.j2objc.translate;

import com.google.common.collect.ImmutableMap;
import com.google.devtools.j2objc.Options;
import com.google.devtools.j2objc.ast.ArrayAccess;
import com.google.devtools.j2objc.ast.ArrayCreation;
Expand All @@ -36,7 +35,6 @@
import com.google.devtools.j2objc.ast.TypeLiteral;
import com.google.devtools.j2objc.types.GeneratedTypeBinding;
import com.google.devtools.j2objc.types.GeneratedVariableBinding;
import com.google.devtools.j2objc.types.IOSMethod;
import com.google.devtools.j2objc.types.IOSMethodBinding;
import com.google.devtools.j2objc.types.IOSTypeBinding;
import com.google.devtools.j2objc.types.Types;
Expand All @@ -48,44 +46,11 @@

/**
* Rewrites array creation into a method invocation on an IOSArray class.
* Must be run after JavaToIOSMethodTranslator because the varargs conversion
* needs to know if the method is mapped.
*
* @author Keith Stanger
*/
public class ArrayRewriter extends TreeVisitor {

private static final ImmutableMap<String, String> INIT_METHODS =
ImmutableMap.<String, String>builder()
.put("IOSBooleanArray", " arrayWithBooleans:(jboolean *)booleans count:(jint)count")
.put("IOSByteArray", " arrayWithBytes:(jbyte *)bytes count:(jint)count")
.put("IOSCharArray", " arrayWithChars:(jchar *)chars count:(jint)count")
.put("IOSDoubleArray", " arrayWithDoubles:(jdouble *)doubles count:(jint)count")
.put("IOSFloatArray", " arrayWithFloats:(jfloat *)floats count:(jint)count")
.put("IOSIntArray", " arrayWithInts:(jint *)ints count:(jint)count")
.put("IOSLongArray", " arrayWithLongs:(jlong *)longs count:(jint)count")
.put("IOSShortArray", " arrayWithShorts:(jshort *)shorts count:(jint)count")
.put("IOSObjectArray",
" arrayWithObjects:(id *)objects count:(jint)count type:(IOSClass *)type")
.build();

private static final ImmutableMap<String, String> RETAINED_INIT_METHODS =
ImmutableMap.<String, String>builder()
.put("IOSBooleanArray", " newArrayWithBooleans:(jboolean *)booleans count:(jint)count")
.put("IOSByteArray", " newArrayWithBytes:(jbyte *)bytes count:(jint)count")
.put("IOSCharArray", " newArrayWithChars:(jchar *)chars count:(jint)count")
.put("IOSDoubleArray", " newArrayWithDoubles:(jdouble *)doubles count:(jint)count")
.put("IOSFloatArray", " newArrayWithFloats:(jfloat *)floats count:(jint)count")
.put("IOSIntArray", " newArrayWithInts:(jint *)ints count:(jint)count")
.put("IOSLongArray", " newArrayWithLongs:(jlong *)longs count:(jint)count")
.put("IOSShortArray", " newArrayWithShorts:(jshort *)shorts count:(jint)count")
.put("IOSObjectArray",
" newArrayWithObjects:(id *)objects count:(jint)count type:(IOSClass *)type")
.build();

private static final IOSMethod ISINSTANCE_METHOD = IOSMethod.create(
"IOSClass isInstance:(id)object");

@Override
public void endVisit(ArrayCreation node) {
node.replaceWith(createInvocation(node));
Expand Down Expand Up @@ -113,7 +78,14 @@ private MethodInvocation newInitializedArrayInvocation(
ITypeBinding componentType = arrayType.getComponentType();
IOSTypeBinding iosArrayBinding = Types.resolveArrayType(componentType);

IOSMethodBinding methodBinding = getInitializeMethod(iosArrayBinding, retainedResult);
IOSMethodBinding methodBinding = IOSMethodBinding.newMethod(
getInitializeSelector(componentType, retainedResult), Modifier.PUBLIC | Modifier.STATIC,
iosArrayBinding, iosArrayBinding);
methodBinding.addParameter(iosArrayBinding);
methodBinding.addParameter(Types.resolveJavaType("int"));
if (!componentType.isPrimitive()) {
methodBinding.addParameter(Types.getIOSClass());
}
MethodInvocation invocation =
new MethodInvocation(methodBinding, new SimpleName(iosArrayBinding));

Expand All @@ -135,28 +107,48 @@ private MethodInvocation newInitializedArrayInvocation(
return invocation;
}

private IOSMethodBinding getInitializeMethod(IOSTypeBinding arrayType, boolean retainedResult) {
String typeName = arrayType.getName();
String methodName =
retainedResult ? RETAINED_INIT_METHODS.get(typeName) : INIT_METHODS.get(typeName);
assert methodName != null;
IOSMethod iosMethod = IOSMethod.create(typeName + methodName);
IOSMethodBinding binding = IOSMethodBinding.newMethod(
iosMethod, Modifier.PUBLIC | Modifier.STATIC, arrayType, arrayType);
binding.addParameter(arrayType);
binding.addParameter(Types.resolveJavaType("int"));
if (arrayType.getName().equals("IOSObjectArray")) {
binding.addParameter(Types.getIOSClass());
private String paramNameForPrimitive(char binaryName) {
switch (binaryName) {
case 'B': return "Bytes";
case 'C': return "Chars";
case 'D': return "Doubles";
case 'F': return "Floats";
case 'I': return "Ints";
case 'J': return "Longs";
case 'S': return "Shorts";
case 'Z': return "Booleans";
}
return binding;
throw new AssertionError("Unknown primitive type: " + binaryName);
}

private String getInitializeSelector(ITypeBinding componentType, boolean retainedResult) {
String selectorFmt = "arrayWith%s:count:";
if (retainedResult) {
selectorFmt = "newArrayWith%s:count:";
}
String paramName;
if (componentType.isPrimitive()) {
paramName = paramNameForPrimitive(componentType.getBinaryName().charAt(0));
} else {
paramName = "Objects";
selectorFmt += "type:";
}
return String.format(selectorFmt, paramName);
}

private MethodInvocation newSingleDimensionArrayInvocation(
ITypeBinding arrayType, Expression dimensionExpr, boolean retainedResult) {
ITypeBinding componentType = arrayType.getComponentType();
IOSTypeBinding iosArrayBinding = Types.resolveArrayType(componentType);

IOSMethodBinding methodBinding = getSingleDimensionMethod(iosArrayBinding, retainedResult);
String selector = (retainedResult ? "newArray" : "array") + "WithLength:"
+ (componentType.isPrimitive() ? "" : "type:");
IOSMethodBinding methodBinding = IOSMethodBinding.newMethod(
selector, Modifier.PUBLIC | Modifier.STATIC, iosArrayBinding, iosArrayBinding);
methodBinding.addParameter(Types.resolveJavaType("int"));
if (!componentType.isPrimitive()) {
methodBinding.addParameter(Types.getIOSClass());
}
MethodInvocation invocation =
new MethodInvocation(methodBinding, new SimpleName(iosArrayBinding));

Expand All @@ -171,31 +163,16 @@ private MethodInvocation newSingleDimensionArrayInvocation(
return invocation;
}

private IOSMethodBinding getSingleDimensionMethod(
IOSTypeBinding arrayType, boolean retainedResult) {
boolean needsTypeParam = arrayType.getName().equals("IOSObjectArray");
IOSMethod iosMethod = IOSMethod.create(
arrayType.getName() + (retainedResult ? " newArray" : " array") + "WithLength:(int)length"
+ (needsTypeParam ? " type:(IOSClass *)type" : ""));
IOSMethodBinding binding = IOSMethodBinding.newMethod(
iosMethod, Modifier.PUBLIC | Modifier.STATIC, arrayType, arrayType);
binding.addParameter(Types.resolveJavaType("int"));
if (needsTypeParam) {
binding.addParameter(Types.getIOSClass());
}
return binding;
}

private MethodInvocation newMultiDimensionArrayInvocation(
ITypeBinding arrayType, List<Expression> dimensions, boolean retainedResult) {
ITypeBinding componentType, List<Expression> dimensions, boolean retainedResult) {
assert dimensions.size() > 1;
ITypeBinding componentType = arrayType;
for (int i = 0; i < dimensions.size(); i++) {
componentType = componentType.getComponentType();
}
IOSTypeBinding iosArrayBinding = Types.resolveArrayType(componentType);

IOSMethodBinding methodBinding = getMultiDimensionMethod(iosArrayBinding, retainedResult);
IOSMethodBinding methodBinding = getMultiDimensionMethod(
componentType, iosArrayBinding, retainedResult);
MethodInvocation invocation =
new MethodInvocation(methodBinding, new SimpleName(iosArrayBinding));

Expand All @@ -218,19 +195,16 @@ private MethodInvocation newMultiDimensionArrayInvocation(
}

private IOSMethodBinding getMultiDimensionMethod(
IOSTypeBinding arrayType, boolean retainedResult) {
boolean needsTypeParam = arrayType.getName().equals("IOSObjectArray");
IOSMethod iosMethod = IOSMethod.create(
arrayType.getName() + (retainedResult ? " newArray" : " array")
+ "WithDimensions:(int)dimensionCount lengths:(int *)dimensionLengths"
+ (needsTypeParam ? " type:(IOSClass *)type" : ""));
ITypeBinding componentType, IOSTypeBinding arrayType, boolean retainedResult) {
String selector = (retainedResult ? "newArray" : "array") + "WithDimensions:lengths:"
+ (componentType.isPrimitive() ? "" : "type:");
IOSMethodBinding binding = IOSMethodBinding.newMethod(
iosMethod, Modifier.PUBLIC | Modifier.STATIC, Types.resolveIOSType("IOSObjectArray"),
selector, Modifier.PUBLIC | Modifier.STATIC, Types.resolveIOSType("IOSObjectArray"),
arrayType);
ITypeBinding intType = Types.resolveJavaType("int");
binding.addParameter(intType);
binding.addParameter(GeneratedTypeBinding.newArrayType(intType));
if (needsTypeParam) {
if (!componentType.isPrimitive()) {
binding.addParameter(Types.getIOSClass());
}
return binding;
Expand Down Expand Up @@ -347,7 +321,7 @@ public void endVisit(InstanceofExpression node) {
return;
}
IOSMethodBinding binding = IOSMethodBinding.newMethod(
ISINSTANCE_METHOD, Modifier.PUBLIC, Types.resolveJavaType("boolean"), Types.getIOSClass());
"isInstance", Modifier.PUBLIC, Types.resolveJavaType("boolean"), Types.getIOSClass());
binding.addParameter(Types.resolveIOSType("id"));
MethodInvocation invocation = new MethodInvocation(binding, newTypeLiteralInvocation(type));
invocation.getArguments().add(TreeUtil.remove(node.getLeftOperand()));
Expand Down
Expand Up @@ -30,7 +30,6 @@
import com.google.devtools.j2objc.ast.TreeUtil;
import com.google.devtools.j2objc.ast.TreeVisitor;
import com.google.devtools.j2objc.ast.VariableDeclarationFragment;
import com.google.devtools.j2objc.types.IOSMethod;
import com.google.devtools.j2objc.types.IOSMethodBinding;
import com.google.devtools.j2objc.types.Types;
import com.google.devtools.j2objc.util.BindingUtil;
Expand All @@ -52,8 +51,6 @@
*/
public class CastResolver extends TreeVisitor {

private static final IOSMethod CLASS_METHOD = IOSMethod.create("NSObject class");

@Override
public void endVisit(CastExpression node) {
ITypeBinding type = node.getType().getTypeBinding();
Expand Down Expand Up @@ -113,8 +110,7 @@ private static FunctionInvocation createCastCheck(ITypeBinding type, Expression
} else if (type.isClass() || type.isArray() || type.isAnnotation() || type.isEnum()) {
invocation = new FunctionInvocation("check_class_cast", idType, idType, null);
invocation.getArguments().add(TreeUtil.remove(expr));
IOSMethodBinding binding = IOSMethodBinding.newMethod(
CLASS_METHOD, Modifier.STATIC, idType, type);
IOSMethodBinding binding = IOSMethodBinding.newMethod("class", Modifier.STATIC, idType, type);
MethodInvocation classInvocation = new MethodInvocation(binding, new SimpleName(type));
invocation.getArguments().add(classInvocation);
}
Expand Down
Expand Up @@ -19,6 +19,8 @@
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;

import java.util.List;

/**
* IOSMethodBinding: synthetic binding for an iOS method.
*
Expand All @@ -27,18 +29,28 @@
public class IOSMethodBinding extends GeneratedMethodBinding {

private final IOSMethod iosMethod;
private final String selector;
private final ITypeBinding[] exceptionTypes;

private static final ITypeBinding[] EMPTY_TYPES = new ITypeBinding[0];

private IOSMethodBinding(
IOSMethod iosMethod, IMethodBinding original, int modifiers, ITypeBinding returnType,
IMethodBinding methodDeclaration, ITypeBinding declaringClass, ITypeBinding[] exceptionTypes,
boolean varargs, boolean synthetic) {
super(original, iosMethod.getName(), modifiers, returnType, methodDeclaration, declaringClass,
false, varargs, synthetic);
IOSMethod iosMethod, String selector, IMethodBinding original, int modifiers,
ITypeBinding returnType, IMethodBinding methodDeclaration, ITypeBinding declaringClass,
ITypeBinding[] exceptionTypes, boolean varargs, boolean synthetic) {
super(original, getName(iosMethod, selector), modifiers, returnType, methodDeclaration,
declaringClass, false, varargs, synthetic);
this.exceptionTypes = exceptionTypes != null ? exceptionTypes : EMPTY_TYPES;
this.iosMethod = iosMethod;
this.selector = selector;
}

private static String getName(IOSMethod iosMethod, String selector) {
if (iosMethod != null) {
return iosMethod.getName();
} else {
return selector;
}
}

public static IOSMethodBinding newMappedMethod(IOSMethod iosMethod, IMethodBinding original) {
Expand All @@ -49,7 +61,7 @@ public static IOSMethodBinding newMappedMethod(IOSMethod iosMethod, IMethodBindi
declaringClass = IOSTypeBinding.newUnmappedClass(iosMethod.getDeclaringClass());
}
IOSMethodBinding binding = new IOSMethodBinding(
iosMethod, original, original.getModifiers(), returnType, null, declaringClass,
iosMethod, null, original, original.getModifiers(), returnType, null, declaringClass,
null, original.isVarargs(), false);
binding.addParameters(original);
return binding;
Expand All @@ -58,7 +70,13 @@ public static IOSMethodBinding newMappedMethod(IOSMethod iosMethod, IMethodBindi
public static IOSMethodBinding newMethod(
IOSMethod iosMethod, int modifiers, ITypeBinding returnType, ITypeBinding declaringClass) {
return new IOSMethodBinding(
iosMethod, null, modifiers, returnType, null, declaringClass, null, false, true);
iosMethod, null, null, modifiers, returnType, null, declaringClass, null, false, true);
}

public static IOSMethodBinding newMethod(
String selector, int modifiers, ITypeBinding returnType, ITypeBinding declaringClass) {
return new IOSMethodBinding(
null, selector, null, modifiers, returnType, null, declaringClass, null, false, true);
}

public static IOSMethod getIOSMethod(IMethodBinding binding) {
Expand All @@ -72,6 +90,25 @@ public IOSMethod getIOSMethod() {
return iosMethod;
}

public String getSelector() {
if (selector != null) {
return selector;
} else {
StringBuilder sb = new StringBuilder(iosMethod.getName());
List<IOSParameter> params = iosMethod.getParameters();
for (int i = 0; i < params.size(); i++) {
if (params.get(i).isVarArgs()) {
break;
}
if (i != 0) {
sb.append(params.get(i).getParameterName());
}
sb.append(":");
}
return sb.toString();
}
}

public static boolean hasVarArgsTarget(IMethodBinding method) {
IOSMethod iosMethod = getIOSMethod(method);
if (iosMethod != null) {
Expand Down
Expand Up @@ -23,9 +23,7 @@
import com.google.devtools.j2objc.ast.CompilationUnit;
import com.google.devtools.j2objc.ast.PackageDeclaration;
import com.google.devtools.j2objc.types.GeneratedVariableBinding;
import com.google.devtools.j2objc.types.IOSMethod;
import com.google.devtools.j2objc.types.IOSMethodBinding;
import com.google.devtools.j2objc.types.IOSParameter;
import com.google.devtools.j2objc.types.PointerTypeBinding;
import com.google.devtools.j2objc.types.Types;
import com.google.j2objc.annotations.ObjectiveCName;
Expand Down Expand Up @@ -409,34 +407,23 @@ public static String parameterKeyword(ITypeBinding type) {
}

public static String getMethodSelector(IMethodBinding method) {
if (method instanceof IOSMethodBinding) {
return ((IOSMethodBinding) method).getSelector();
}
StringBuilder sb = new StringBuilder();
if (method.isConstructor()) {
sb.append("init");
} else {
sb.append(getName(method));
}
IOSMethod iosMethod = IOSMethodBinding.getIOSMethod(method);
if (iosMethod != null) {
List<IOSParameter> params = iosMethod.getParameters();
for (int i = 0; i < params.size(); i++) {
if (params.get(i).isVarArgs()) {
break;
}
if (i != 0) {
sb.append(params.get(i).getParameterName());
}
sb.append(":");
}
} else {
method = BindingUtil.getOriginalMethodBinding(method);
ITypeBinding[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String keyword = NameTable.parameterKeyword(paramTypes[i]);
if (i == 0) {
keyword = NameTable.capitalize(keyword);
}
sb.append(keyword).append(":");
method = BindingUtil.getOriginalMethodBinding(method);
ITypeBinding[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String keyword = NameTable.parameterKeyword(paramTypes[i]);
if (i == 0) {
keyword = NameTable.capitalize(keyword);
}
sb.append(keyword).append(":");
}
return sb.toString();
}
Expand Down

0 comments on commit b30480f

Please sign in to comment.