Skip to content

Commit

Permalink
Remove uses of IOSMethod and allow method renamings to be specified w…
Browse files Browse the repository at this point in the history
…ith simple selector strings.

	Change on 2015/02/18 by kstanger <kstanger@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=86597872
  • Loading branch information
kstanger committed Feb 25, 2015
1 parent 0a618f3 commit 42bc82e
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 70 deletions.
Expand Up @@ -709,21 +709,7 @@ public boolean visit(ReturnStatement node) {
MethodDeclaration method = TreeUtil.getOwningMethod(node);
if (expr != null) {
buffer.append(' ');
boolean shouldRetainResult = false;

// In manual reference counting mode, per convention, -copyWithZone: should return
// an object with a reference count of +1.
if (method != null && method.getName().getIdentifier().equals("copyWithZone")
&& useReferenceCounting) {
shouldRetainResult = true;
}
if (shouldRetainResult) {
buffer.append("[");
}
expr.accept(this);
if (shouldRetainResult) {
buffer.append(" retain]");
}
} else if (method != null && method.getMethodBinding().isConstructor()) {
// A return statement without any expression is allowed in constructors.
buffer.append(" self");
Expand Down
Expand Up @@ -29,7 +29,6 @@
import com.google.devtools.j2objc.ast.TreeVisitor;
import com.google.devtools.j2objc.ast.TypeDeclaration;
import com.google.devtools.j2objc.ast.VariableDeclaration;
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 @@ -49,8 +48,7 @@
*/
public class JavaCloneWriter extends TreeVisitor {

private static final IOSMethod NSOBJECT_JAVA_CLONE = IOSMethod.create("NSObject __javaClone");
private static final IOSMethod NSOBJECT_RELEASE = IOSMethod.create("NSObject release");
private static final String JAVA_CLONE_METHOD = "__javaClone";

private static final Function<VariableDeclaration, IVariableBinding> GET_VARIABLE_BINDING_FUNC =
new Function<VariableDeclaration, IVariableBinding>() {
Expand All @@ -75,9 +73,9 @@ public JavaCloneWriter() {
ITypeBinding voidType = Types.resolveJavaType("void");
ITypeBinding nsObjectType = Types.resolveIOSType("NSObject");
nsObjectJavaClone = IOSMethodBinding.newMethod(
NSOBJECT_JAVA_CLONE, Modifier.PUBLIC, voidType, nsObjectType);
JAVA_CLONE_METHOD, Modifier.PUBLIC, voidType, nsObjectType);
releaseBinding = IOSMethodBinding.newMethod(
NSOBJECT_RELEASE, Modifier.PUBLIC, voidType, nsObjectType);
NameTable.RELEASE_METHOD, Modifier.PUBLIC, voidType, nsObjectType);
}

@Override
Expand All @@ -88,11 +86,9 @@ public void endVisit(TypeDeclaration node) {
return;
}

String typeName = NameTable.getFullName(type);
IOSMethod iosMethod = IOSMethod.create(String.format("%s __javaClone", typeName));
int modifiers = Modifier.PUBLIC | BindingUtil.ACC_SYNTHETIC;
IOSMethodBinding methodBinding = IOSMethodBinding.newMethod(
iosMethod, modifiers, Types.resolveJavaType("void"), type);
JAVA_CLONE_METHOD, modifiers, Types.resolveJavaType("void"), type);

MethodDeclaration declaration = new MethodDeclaration(methodBinding);
node.getBodyDeclarations().add(declaration);
Expand Down
Expand Up @@ -16,8 +16,7 @@

package com.google.devtools.j2objc.translate;

import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.devtools.j2objc.Options;
import com.google.devtools.j2objc.ast.Block;
import com.google.devtools.j2objc.ast.ClassInstanceCreation;
import com.google.devtools.j2objc.ast.Expression;
Expand All @@ -31,7 +30,6 @@
import com.google.devtools.j2objc.ast.TypeDeclaration;
import com.google.devtools.j2objc.types.GeneratedMethodBinding;
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.Types;
import com.google.devtools.j2objc.util.BindingUtil;
Expand All @@ -57,18 +55,10 @@ public class JavaToIOSMethodTranslator extends TreeVisitor {

private final ITypeBinding javaLangCloneable;

private final Map<String, IOSMethod> methodMappings;

private static final Function<String, IOSMethod> IOS_METHOD_FROM_STRING =
new Function<String, IOSMethod>() {
public IOSMethod apply(String value) {
return IOSMethod.create(value);
}
};
private final Map<String, String> methodMappings;

public JavaToIOSMethodTranslator(Map<String, String> methodMappings) {
this.methodMappings =
Maps.newHashMap(Maps.transformValues(methodMappings, IOS_METHOD_FROM_STRING));
this.methodMappings = NameTable.getMethodMappings();
javaLangCloneable = Types.resolveJavaType("java.lang.Cloneable");
}

Expand All @@ -79,9 +69,7 @@ public boolean visit(MethodDeclaration node) {
// Check if @ObjectiveCName is used but is mismatched with an overriden method.
IAnnotationBinding annotation = BindingUtil.getAnnotation(method, ObjectiveCName.class);
if (annotation != null) {
String value = (String) BindingUtil.getAnnotationValue(annotation, "value");
String selector =
IOSMethod.create(method.getDeclaringClass().getName() + " " + value).getSelector();
String selector = NameTable.getMethodSelectorFromAnnotation(method);
String actualSelector = NameTable.getMethodSelector(method);
if (!selector.equals(actualSelector)) {
ErrorUtil.warning("ObjectiveCName(" + selector
Expand All @@ -106,8 +94,8 @@ public boolean visit(ClassInstanceCreation node) {

IMethodBinding binding = node.getMethodBinding();
String key = BindingUtil.getMethodKey(binding);
IOSMethod iosMethod = methodMappings.get(key);
if (iosMethod != null) {
String selector = methodMappings.get(key);
if (selector != null) {
assert !node.hasRetainedResult();
if (key.equals("java.lang.String.String(Ljava/lang/String;)V")) {
// Special case: replace new String(constant) to constant (avoid clang warning).
Expand All @@ -117,9 +105,9 @@ public boolean visit(ClassInstanceCreation node) {
return false;
}
}
IOSMethodBinding methodBinding = IOSMethodBinding.newMappedMethod(iosMethod, binding);
MethodInvocation newInvocation = new MethodInvocation(methodBinding,
new SimpleName(Types.resolveIOSType(iosMethod.getDeclaringClass())));
IOSMethodBinding methodBinding = IOSMethodBinding.newMappedMethod(selector, binding);
MethodInvocation newInvocation = new MethodInvocation(
methodBinding, new SimpleName(binding.getDeclaringClass()));

// Set parameters.
copyInvocationArguments(null, node.getArguments(), newInvocation.getArguments());
Expand Down Expand Up @@ -157,18 +145,14 @@ private void copyInvocationArguments(Expression receiver, List<Expression> oldAr
}
}

private MethodInvocation makeCloneInvocation(ITypeBinding declaringClass) {
GeneratedMethodBinding cloneBinding = GeneratedMethodBinding.newMethod(
"clone", 0, Types.resolveIOSType("NSObject"), declaringClass);
return new MethodInvocation(cloneBinding, null);
}

private void addCopyWithZoneMethod(TypeDeclaration node) {
// Create copyWithZone: method.
ITypeBinding type = node.getTypeBinding().getTypeDeclaration();
IOSMethod iosMethod = IOSMethod.create("id copyWithZone:(NSZone *)zone");
ITypeBinding idType = Types.resolveIOSType("id");
ITypeBinding nsObjectType = Types.resolveIOSType("NSObject");

IOSMethodBinding binding = IOSMethodBinding.newMethod(
iosMethod, Modifier.PUBLIC, Types.resolveIOSType("id"), type);
"copyWithZone:", Modifier.PUBLIC, idType, type);
MethodDeclaration cloneMethod = new MethodDeclaration(binding);

// Add NSZone *zone parameter.
Expand All @@ -181,8 +165,15 @@ private void addCopyWithZoneMethod(TypeDeclaration node) {
Block block = new Block();
cloneMethod.setBody(block);

MethodInvocation cloneInvocation = makeCloneInvocation(type);
block.getStatements().add(new ReturnStatement(cloneInvocation));
GeneratedMethodBinding cloneBinding = GeneratedMethodBinding.newMethod(
"clone", 0, nsObjectType, type);
MethodInvocation invocation = new MethodInvocation(cloneBinding, null);
if (Options.useReferenceCounting()) {
IOSMethodBinding retainBinding = IOSMethodBinding.newMethod(
NameTable.RETAIN_METHOD, Modifier.PUBLIC, idType, nsObjectType);
invocation = new MethodInvocation(retainBinding, invocation);
}
block.getStatements().add(new ReturnStatement(invocation));

node.getBodyDeclarations().add(cloneMethod);
}
Expand Down
Expand Up @@ -65,6 +65,16 @@ public static IOSMethodBinding newMappedMethod(IOSMethod iosMethod, IMethodBindi
return binding;
}

public static IOSMethodBinding newMappedMethod(String selector, IMethodBinding original) {
ITypeBinding returnType =
original.isConstructor() ? original.getDeclaringClass() : original.getReturnType();
IOSMethodBinding binding = new IOSMethodBinding(
null, selector, original, original.getModifiers(), returnType, null,
original.getDeclaringClass(), null, original.isVarargs(), false);
binding.addParameters(original);
return binding;
}

public static IOSMethodBinding newMethod(
IOSMethod iosMethod, int modifiers, ITypeBinding returnType, ITypeBinding declaringClass) {
return new IOSMethodBinding(
Expand Down
Expand Up @@ -25,7 +25,6 @@
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.PointerTypeBinding;
import com.google.devtools.j2objc.types.Types;
Expand All @@ -46,6 +45,8 @@
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Singleton service for type/method/variable name support.
Expand All @@ -59,6 +60,8 @@ public class NameTable {
private final PathClassLoader classLoader;

public static final String INIT_NAME = "init";
public static final String RETAIN_METHOD = "retain";
public static final String RELEASE_METHOD = "release";
public static final String DEALLOC_METHOD = "dealloc";
public static final String FINALIZE_METHOD = "finalize";

Expand Down Expand Up @@ -251,12 +254,12 @@ public class NameTable {
*/
private final Map<String, String> prefixMap;

private final Map<String, IOSMethod> methodMappings;
private final Map<String, String> methodMappings;

private static final Function<String, IOSMethod> IOS_METHOD_FROM_STRING =
new Function<String, IOSMethod>() {
public IOSMethod apply(String value) {
return IOSMethod.create(value);
private static final Function<String, String> EXTRACT_SELECTOR_FUNC =
new Function<String, String>() {
public String apply(String value) {
return extractMethodSelector(value);
}
};

Expand All @@ -265,7 +268,7 @@ private NameTable(
PathClassLoader classLoader) {
this.prefixMap = prefixMap;
this.methodMappings =
Maps.newHashMap(Maps.transformValues(rawMethodMappings, IOS_METHOD_FROM_STRING));
Maps.newHashMap(Maps.transformValues(rawMethodMappings, EXTRACT_SELECTOR_FUNC));
this.classLoader = classLoader;
}

Expand Down Expand Up @@ -428,6 +431,42 @@ public static String parameterKeyword(ITypeBinding type) {
return "with" + capitalize(getParameterTypeKeyword(type));
}

// Needed by JavaToIOSMethodTranslator to convert ClassInstanceCreation nodes
// to MethodInvocation nodes.
public static Map<String, String> getMethodMappings() {
return instance.methodMappings;
}

// Matches the class name prefix or a parameter declarations of a method
// signature. After removing these parts, the selector remains.
private static final Pattern SIGNATURE_STRIPPER =
Pattern.compile("^\\w* |\\s*\\([^)]*\\)\\s*\\w+\\s*");

// TODO(kstanger): Phase out usage of full method signatures when renaming methods.
private static String parseSelectorFromSignature(String s) {
if (s.endsWith(";")) {
s = s.substring(0, s.length() - 1);
}
Matcher matcher = SIGNATURE_STRIPPER.matcher(s);
return matcher.replaceAll("");
}

private static final Pattern SELECTOR_VALIDATOR = Pattern.compile("\\w+|(\\w+\\:)+");

private static void validateMethodSelector(String selector) {
if (!SELECTOR_VALIDATOR.matcher(selector).matches()) {
ErrorUtil.error("Invalid method selector: " + selector);
}
}

private static String extractMethodSelector(String value) {
if (value.contains(" ")) {
value = parseSelectorFromSignature(value);
}
validateMethodSelector(value);
return value;
}

public static String getMethodName(IMethodBinding method) {
if (method.isConstructor()) {
return "init";
Expand All @@ -447,11 +486,11 @@ public static String getMethodSelector(IMethodBinding method) {
return DEALLOC_METHOD;
}
method = getOriginalMethodBinding(method);
IOSMethod iosMethod = instance.methodMappings.get(BindingUtil.getMethodKey(method));
if (iosMethod != null) {
return iosMethod.getSelector();
String selector = instance.methodMappings.get(BindingUtil.getMethodKey(method));
if (selector != null) {
return selector;
}
String selector = getMethodSelectorFromAnnotation(method);
selector = getMethodSelectorFromAnnotation(method);
if (selector != null) {
return selector;
}
Expand Down Expand Up @@ -488,11 +527,11 @@ public static String makeFunctionName(IMethodBinding method) {
return sb.toString();
}

private static String getMethodSelectorFromAnnotation(IMethodBinding method) {
public static String getMethodSelectorFromAnnotation(IMethodBinding method) {
IAnnotationBinding annotation = BindingUtil.getAnnotation(method, ObjectiveCName.class);
if (annotation != null) {
String value = (String) BindingUtil.getAnnotationValue(annotation, "value");
return IOSMethod.create(method.getDeclaringClass().getName() + " " + value).getSelector();
return extractMethodSelector(value);
}
return null;
}
Expand Down
Expand Up @@ -148,8 +148,15 @@ public void testRenameMapping() throws IOException {
}
}

public void testRenameMethodAnnotation() throws IOException {
String objcName = "test:(NSString *)s offset:(int)n";
public void testRenameMethodAnnotationWithFullSignature() throws IOException {
checkRenameMethodAnnotation("test:(NSString *)s offset:(int)n");
}

public void testRenameMethodAnnotationWithSelector() throws IOException {
checkRenameMethodAnnotation("test:offset:");
}

public void checkRenameMethodAnnotation(String objcName) throws IOException {
addSourceFile("public class A { "
+ "@com.google.j2objc.annotations.ObjectiveCName(\"" + objcName + "\") "
+ "void test(String s, int n) {}}", "A.java");
Expand All @@ -170,8 +177,15 @@ public void testRenameMethodAnnotation() throws IOException {
assertTranslation(translation, "[((A *) nil_chk(a)) test:@\"foo\" offset:4];");
}

public void testRenameConstructorAnnotation() throws IOException {
String objcName = "init:(NSString *)s offset:(int)n";
public void testRenameConstructorAnnotationWithFullSignature() throws IOException {
checkRenameConstructorAnnotation("init:(NSString *)s offset:(int)n");
}

public void testRenameConstructorAnnotationWithSelector() throws IOException {
checkRenameConstructorAnnotation("init:offset:");
}

public void checkRenameConstructorAnnotation(String objcName) throws IOException {
addSourceFile("public class A { "
+ "@com.google.j2objc.annotations.ObjectiveCName(\"" + objcName + "\") "
+ "A(String s, int n) {}}", "A.java");
Expand Down

0 comments on commit 42bc82e

Please sign in to comment.