aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-04-02 15:55:37 +0100
committerMichael Williamson <mike@zwobble.org>2016-04-02 15:55:37 +0100
commitc6f690724da284c8065319252bf79eb166a168c8 (patch)
tree8dabaa3fcc11f35711fb2e610e8808a8cac5b9d0
parentd2c63996ece9bb9184a17d5bb24ae03e87eb87f5 (diff)
Read qualified names when qualifier is a variable reference
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java16
-rw-r--r--src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java23
-rw-r--r--src/test/java/org/zwobble/couscous/tests/frontends/java/NodeMatchers.java39
3 files changed, 74 insertions, 4 deletions
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
index 0154b1d..e9d6195 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
@@ -15,11 +15,13 @@ import java.util.stream.IntStream;
import static org.zwobble.couscous.ast.ArrayNode.array;
import static org.zwobble.couscous.ast.CastNode.cast;
import static org.zwobble.couscous.ast.ConstructorCallNode.constructorCall;
+import static org.zwobble.couscous.ast.InstanceReceiver.instanceReceiver;
import static org.zwobble.couscous.ast.LiteralNode.literal;
import static org.zwobble.couscous.ast.MethodCallNode.methodCall;
import static org.zwobble.couscous.ast.MethodCallNode.staticMethodCall;
import static org.zwobble.couscous.ast.OperationNode.operation;
import static org.zwobble.couscous.ast.Operations.not;
+import static org.zwobble.couscous.ast.StaticReceiver.staticReceiver;
import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference;
import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion;
import static org.zwobble.couscous.frontends.java.JavaOperators.readOperator;
@@ -192,12 +194,24 @@ public class JavaExpressionReader {
}
private ExpressionNode readQualifiedName(QualifiedName expression) {
+ Receiver receiver = toReceiver(expression.getQualifier().resolveBinding());
return FieldAccessNode.fieldAccess(
- ScalarType.of(((ITypeBinding)expression.getQualifier().resolveBinding()).getQualifiedName()),
+ receiver,
expression.getName().getIdentifier(),
typeOf(expression));
}
+ private Receiver toReceiver(IBinding binding) {
+ if (binding instanceof ITypeBinding) {
+ ScalarType receiver = ScalarType.of(((ITypeBinding) binding).getQualifiedName());
+ return staticReceiver(receiver);
+ } else if (binding instanceof IVariableBinding) {
+ return instanceReceiver(readVariableBinding((IVariableBinding) binding));
+ } else {
+ throw new UnsupportedOperationException("Unsupported binding: " + binding);
+ }
+ }
+
private ExpressionNode readMethodInvocation(MethodInvocation expression) {
String methodName = expression.getName().getIdentifier();
@SuppressWarnings("unchecked")
diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java
index 7055ecd..72646bc 100644
--- a/src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java
@@ -8,6 +8,7 @@ import org.zwobble.couscous.types.Types;
import java.util.List;
import static java.util.Collections.emptyList;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.zwobble.couscous.ast.ArrayNode.array;
import static org.zwobble.couscous.ast.AssignmentNode.assign;
@@ -20,12 +21,12 @@ import static org.zwobble.couscous.ast.LiteralNode.literal;
import static org.zwobble.couscous.ast.MethodCallNode.methodCall;
import static org.zwobble.couscous.ast.MethodCallNode.staticMethodCall;
import static org.zwobble.couscous.ast.Operations.*;
-import static org.zwobble.couscous.ast.Operations.unboxInt;
import static org.zwobble.couscous.ast.TernaryConditionalNode.ternaryConditional;
import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference;
import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion;
import static org.zwobble.couscous.ast.VariableReferenceNode.reference;
import static org.zwobble.couscous.tests.frontends.java.JavaReading.*;
+import static org.zwobble.couscous.tests.frontends.java.NodeMatchers.*;
import static org.zwobble.couscous.types.ParameterizedType.parameterizedType;
import static org.zwobble.couscous.util.ExtraLists.list;
@@ -74,12 +75,12 @@ public class ExpressionReadingTests {
}
@Test
- public void canReadExplicitFieldReference() {
+ public void canReadFieldReferenceWithExplicitThis() {
canReadFieldReference("this.name");
}
@Test
- public void canReadImplicitFieldReference() {
+ public void canReadFieldReferenceWithImplicitThis() {
canReadFieldReference("name");
}
@@ -100,6 +101,22 @@ public class ExpressionReadingTests {
}
@Test
+ public void canReadFieldReferenceWithVariableReceiver() {
+ ClassNode classNode = readClass(
+ "private String name;" +
+ "public String getName() {" +
+ " Example self = this;" +
+ " return self.name;" +
+ "}");
+
+ ReturnNode returnNode = (ReturnNode) classNode.getMethods().get(0).getBody().get().get(1);
+ assertThat(returnNode.getValue(), isFieldAccess(
+ fieldHasReceiver(isVariableReference("self", ScalarType.of("com.example.Example"))),
+ fieldHasName("name"),
+ expressionHasType(Types.STRING)));
+ }
+
+ @Test
public void canReadExplicitStaticFieldReferenceWithSimplyNamedClassAsReceiver() {
canReadStaticFieldReference("Example.name");
}
diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/NodeMatchers.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/NodeMatchers.java
new file mode 100644
index 0000000..739d664
--- /dev/null
+++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/NodeMatchers.java
@@ -0,0 +1,39 @@
+package org.zwobble.couscous.tests.frontends.java;
+
+import org.hamcrest.Matcher;
+import org.zwobble.couscous.ast.*;
+import org.zwobble.couscous.types.Type;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.equalTo;
+import static org.zwobble.couscous.tests.util.ExtraMatchers.hasFeature;
+import static org.zwobble.couscous.tests.util.ExtraMatchers.isInstance;
+
+public class NodeMatchers {
+ @SafeVarargs
+ public static Matcher<ExpressionNode> isFieldAccess(Matcher<? super FieldAccessNode>... matchers) {
+ return isInstance(FieldAccessNode.class, allOf(matchers));
+ }
+
+ public static Matcher<ExpressionNode> isVariableReference(String name, Type type) {
+ return isInstance(VariableReferenceNode.class, allOf(
+ hasFeature("variable name", node -> node.getReferent().getName(), equalTo(name)),
+ expressionHasType(type)));
+ }
+
+ public static Matcher<FieldAccessNode> fieldHasReceiver(Matcher<ExpressionNode> receiverMatcher) {
+ return hasFeature("receiver", FieldAccessNode::getLeft, isInstanceReceiver(receiverMatcher));
+ }
+
+ public static Matcher<Receiver> isInstanceReceiver(Matcher<ExpressionNode> receiverMatcher) {
+ return isInstance(InstanceReceiver.class, hasFeature("value", receiver -> receiver.getExpression(), receiverMatcher));
+ }
+
+ public static Matcher<FieldAccessNode> fieldHasName(String name) {
+ return hasFeature("field name", FieldAccessNode::getFieldName, equalTo(name));
+ }
+
+ public static Matcher<ExpressionNode> expressionHasType(Type type) {
+ return hasFeature("type", ExpressionNode::getType, equalTo(type));
+ }
+}