Skip to content

Commit

Permalink
Adds more specific type binding information to MethodInvocation nodes…
Browse files Browse the repository at this point in the history
…. The specific type of the expression may differ from the return type of its method binding. This helps CastResolver omit cast checks on arrays in some cases.

	Change on 2015/11/20 by kstanger <kstanger@google.com>
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=108337719
  • Loading branch information
kstanger authored and tomball committed Nov 25, 2015
1 parent e9c9caa commit 87ed715
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 11 deletions.
Expand Up @@ -27,13 +27,16 @@
public class MethodInvocation extends Expression { public class MethodInvocation extends Expression {


private IMethodBinding methodBinding = null; private IMethodBinding methodBinding = null;
// The context-specific known type of this expression.
private ITypeBinding typeBinding = null;
private ChildLink<Expression> expression = ChildLink.create(Expression.class, this); private ChildLink<Expression> expression = ChildLink.create(Expression.class, this);
private ChildLink<SimpleName> name = ChildLink.create(SimpleName.class, this); private ChildLink<SimpleName> name = ChildLink.create(SimpleName.class, this);
private ChildList<Expression> arguments = ChildList.create(Expression.class, this); private ChildList<Expression> arguments = ChildList.create(Expression.class, this);


public MethodInvocation(org.eclipse.jdt.core.dom.MethodInvocation jdtNode) { public MethodInvocation(org.eclipse.jdt.core.dom.MethodInvocation jdtNode) {
super(jdtNode); super(jdtNode);
methodBinding = jdtNode.resolveMethodBinding(); methodBinding = jdtNode.resolveMethodBinding();
typeBinding = jdtNode.resolveTypeBinding();
expression.set((Expression) TreeConverter.convert(jdtNode.getExpression())); expression.set((Expression) TreeConverter.convert(jdtNode.getExpression()));
name.set((SimpleName) TreeConverter.convert(jdtNode.getName())); name.set((SimpleName) TreeConverter.convert(jdtNode.getName()));
for (Object argument : jdtNode.arguments()) { for (Object argument : jdtNode.arguments()) {
Expand All @@ -44,17 +47,23 @@ public MethodInvocation(org.eclipse.jdt.core.dom.MethodInvocation jdtNode) {
public MethodInvocation(MethodInvocation other) { public MethodInvocation(MethodInvocation other) {
super(other); super(other);
methodBinding = other.getMethodBinding(); methodBinding = other.getMethodBinding();
typeBinding = other.getTypeBinding();
expression.copyFrom(other.getExpression()); expression.copyFrom(other.getExpression());
name.copyFrom(other.getName()); name.copyFrom(other.getName());
arguments.copyFrom(other.getArguments()); arguments.copyFrom(other.getArguments());
} }


public MethodInvocation(IMethodBinding binding, Expression expression) { public MethodInvocation(IMethodBinding binding, ITypeBinding typeBinding, Expression expression) {
methodBinding = binding; methodBinding = binding;
this.typeBinding = typeBinding;
this.expression.set(expression); this.expression.set(expression);
name.set(new SimpleName(binding)); name.set(new SimpleName(binding));
} }


public MethodInvocation(IMethodBinding binding, Expression expression) {
this(binding, binding.getReturnType(), expression);
}

@Override @Override
public Kind getKind() { public Kind getKind() {
return Kind.METHOD_INVOCATION; return Kind.METHOD_INVOCATION;
Expand All @@ -70,7 +79,11 @@ public void setMethodBinding(IMethodBinding newMethodBinding) {


@Override @Override
public ITypeBinding getTypeBinding() { public ITypeBinding getTypeBinding() {
return methodBinding != null ? methodBinding.getReturnType() : null; return typeBinding;
}

public void setTypeBinding(ITypeBinding newTypeBinding) {
typeBinding = newTypeBinding;
} }


public Expression getExpression() { public Expression getExpression() {
Expand Down
Expand Up @@ -86,7 +86,7 @@ private MethodInvocation newInitializedArrayInvocation(
methodBinding.addParameter(typeEnv.getIOSClass()); methodBinding.addParameter(typeEnv.getIOSClass());
} }
MethodInvocation invocation = MethodInvocation invocation =
new MethodInvocation(methodBinding, new SimpleName(iosArrayBinding)); new MethodInvocation(methodBinding, arrayType, new SimpleName(iosArrayBinding));


// Create the array initializer and add it as the first parameter. // Create the array initializer and add it as the first parameter.
ArrayInitializer arrayInit = new ArrayInitializer(arrayType); ArrayInitializer arrayInit = new ArrayInitializer(arrayType);
Expand Down Expand Up @@ -150,7 +150,7 @@ private MethodInvocation newSingleDimensionArrayInvocation(
methodBinding.addParameter(typeEnv.getIOSClass()); methodBinding.addParameter(typeEnv.getIOSClass());
} }
MethodInvocation invocation = MethodInvocation invocation =
new MethodInvocation(methodBinding, new SimpleName(iosArrayBinding)); new MethodInvocation(methodBinding, arrayType, new SimpleName(iosArrayBinding));


// Add the array length argument. // Add the array length argument.
invocation.getArguments().add(dimensionExpr.copy()); invocation.getArguments().add(dimensionExpr.copy());
Expand All @@ -164,8 +164,9 @@ private MethodInvocation newSingleDimensionArrayInvocation(
} }


private MethodInvocation newMultiDimensionArrayInvocation( private MethodInvocation newMultiDimensionArrayInvocation(
ITypeBinding componentType, List<Expression> dimensions, boolean retainedResult) { ITypeBinding arrayType, List<Expression> dimensions, boolean retainedResult) {
assert dimensions.size() > 1; assert dimensions.size() > 1;
ITypeBinding componentType = arrayType;
for (int i = 0; i < dimensions.size(); i++) { for (int i = 0; i < dimensions.size(); i++) {
componentType = componentType.getComponentType(); componentType = componentType.getComponentType();
} }
Expand All @@ -174,7 +175,7 @@ private MethodInvocation newMultiDimensionArrayInvocation(
IOSMethodBinding methodBinding = getMultiDimensionMethod( IOSMethodBinding methodBinding = getMultiDimensionMethod(
componentType, iosArrayBinding, retainedResult); componentType, iosArrayBinding, retainedResult);
MethodInvocation invocation = MethodInvocation invocation =
new MethodInvocation(methodBinding, new SimpleName(iosArrayBinding)); new MethodInvocation(methodBinding, arrayType, new SimpleName(iosArrayBinding));


// Add the dimension count argument. // Add the dimension count argument.
invocation.getArguments().add(NumberLiteral.newIntLiteral(dimensions.size(), typeEnv)); invocation.getArguments().add(NumberLiteral.newIntLiteral(dimensions.size(), typeEnv));
Expand All @@ -195,12 +196,12 @@ private MethodInvocation newMultiDimensionArrayInvocation(
} }


private IOSMethodBinding getMultiDimensionMethod( private IOSMethodBinding getMultiDimensionMethod(
ITypeBinding componentType, IOSTypeBinding arrayType, boolean retainedResult) { ITypeBinding componentType, IOSTypeBinding iosArrayType, boolean retainedResult) {
String selector = (retainedResult ? "newArray" : "array") + "WithDimensions:lengths:" String selector = (retainedResult ? "newArray" : "array") + "WithDimensions:lengths:"
+ (componentType.isPrimitive() ? "" : "type:"); + (componentType.isPrimitive() ? "" : "type:");
IOSMethodBinding binding = IOSMethodBinding.newMethod( IOSMethodBinding binding = IOSMethodBinding.newMethod(
selector, Modifier.PUBLIC | Modifier.STATIC, typeEnv.resolveIOSType("IOSObjectArray"), selector, Modifier.PUBLIC | Modifier.STATIC, typeEnv.resolveIOSType("IOSObjectArray"),
arrayType); iosArrayType);
ITypeBinding intType = typeEnv.resolveJavaType("int"); ITypeBinding intType = typeEnv.resolveJavaType("int");
binding.addParameter(intType); binding.addParameter(intType);
binding.addParameter(GeneratedTypeBinding.newArrayType(intType)); binding.addParameter(GeneratedTypeBinding.newArrayType(intType));
Expand Down
Expand Up @@ -165,7 +165,7 @@ private boolean needsCast(Expression expr, ITypeBinding expectedType, boolean sh
// In most cases we don't need to cast from an id type. However, if the // In most cases we don't need to cast from an id type. However, if the
// expression is being dereferenced then the compiler needs the type // expression is being dereferenced then the compiler needs the type
// info. // info.
|| (declaredType == typeEnv.getIdType() && !shouldCastFromId) || (typeEnv.isIdType(declaredType) && !shouldCastFromId)
// If the declared type can be assigned into the actual type, or the // If the declared type can be assigned into the actual type, or the
// expected type, then the compiler already has sufficient type info. // expected type, then the compiler already has sufficient type info.
|| typeEnv.isIdType(exprType) || typeEnv.isIdType(expectedType) || typeEnv.isIdType(exprType) || typeEnv.isIdType(expectedType)
Expand Down
Expand Up @@ -222,8 +222,11 @@ public void testInterfaceComparisons() throws IOException {


public void testGenericArrayCast() throws IOException { public void testGenericArrayCast() throws IOException {
String translation = translateSourceFile( String translation = translateSourceFile(
"class Test<E> { E[] test(Object[] o) { return (E[])o; } }", "Test", "Test.m"); "class Test<E> { E[] test(Object[] o) { E[] e = (E[]) new Object[0]; return (E[])o; } }",
// No need to check the cast because the erasure of E[] is Object[]. "Test", "Test.m");
// No need to check either cast because the erasure of E[] is Object[].
assertTranslation(translation,
"IOSObjectArray *e = [IOSObjectArray arrayWithLength:0 type:NSObject_class_()];");
assertTranslation(translation, "return o;"); assertTranslation(translation, "return o;");
translation = translateSourceFile( translation = translateSourceFile(
"class Test<E extends String> { E[] test(Object[] o) { return (E[])o; } }", "class Test<E extends String> { E[] test(Object[] o) { return (E[])o; } }",
Expand Down

0 comments on commit 87ed715

Please sign in to comment.