improve isAssignableBy when Wildcards are involved
diff --git a/java-symbol-solver-core/src/main/java/me/tomassetti/symbolsolver/model/typesystem/ReferenceTypeUsageImpl.java b/java-symbol-solver-core/src/main/java/me/tomassetti/symbolsolver/model/typesystem/ReferenceTypeUsageImpl.java
index ffcdc2b..cf9e091 100644
--- a/java-symbol-solver-core/src/main/java/me/tomassetti/symbolsolver/model/typesystem/ReferenceTypeUsageImpl.java
+++ b/java-symbol-solver-core/src/main/java/me/tomassetti/symbolsolver/model/typesystem/ReferenceTypeUsageImpl.java
@@ -70,6 +70,14 @@
} else if (other.isTypeVariable()) {
// TODO look bounds...
return true;
+ } else if (other.isWildcard()) {
+ if (this.getQualifiedName().equals(Object.class.getCanonicalName())) {
+ return true;
+ } else if (other.asWildcard().isExtends()) {
+ return isAssignableBy(other.asWildcard().getBoundedType());
+ } else {
+ return false;
+ }
} else {
return false;
}
diff --git a/java-symbol-solver-core/src/main/java/me/tomassetti/symbolsolver/resolution/javaparser/contexts/MethodCallExprContext.java b/java-symbol-solver-core/src/main/java/me/tomassetti/symbolsolver/resolution/javaparser/contexts/MethodCallExprContext.java
index 05f92f9..ac1fcd3 100644
--- a/java-symbol-solver-core/src/main/java/me/tomassetti/symbolsolver/resolution/javaparser/contexts/MethodCallExprContext.java
+++ b/java-symbol-solver-core/src/main/java/me/tomassetti/symbolsolver/resolution/javaparser/contexts/MethodCallExprContext.java
@@ -7,9 +7,7 @@
import me.tomassetti.symbolsolver.model.declarations.ValueDeclaration;
import me.tomassetti.symbolsolver.model.invokations.MethodUsage;
import me.tomassetti.symbolsolver.model.resolution.*;
-import me.tomassetti.symbolsolver.model.typesystem.ReferenceTypeUsageImpl;
-import me.tomassetti.symbolsolver.model.typesystem.TypeParameterUsage;
-import me.tomassetti.symbolsolver.model.typesystem.TypeUsage;
+import me.tomassetti.symbolsolver.model.typesystem.*;
import me.tomassetti.symbolsolver.resolution.javaparser.JavaParserFacade;
import me.tomassetti.symbolsolver.resolution.javaparser.UnsolvedSymbolException;
import me.tomassetti.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
@@ -32,7 +30,7 @@
return typeOfScope.asReferenceTypeUsage().getGenericParameterByName(name);
}
- private Optional<MethodUsage> solveMethodAsUsage(ReferenceTypeUsageImpl refType, String name, List<TypeUsage> parameterTypes, TypeSolver typeSolver, Context invokationContext) {
+ private Optional<MethodUsage> solveMethodAsUsage(ReferenceTypeUsage refType, String name, List<TypeUsage> parameterTypes, TypeSolver typeSolver, Context invokationContext) {
Optional<MethodUsage> ref = refType.getTypeDeclaration().solveMethodAsUsage(name, parameterTypes, typeSolver, invokationContext, refType.parameters());
if (ref.isPresent()) {
MethodUsage methodUsage = ref.get();
@@ -66,12 +64,21 @@
}
private Optional<MethodUsage> solveMethodAsUsage(TypeUsage typeUsage, String name, List<TypeUsage> parameterTypes, TypeSolver typeSolver, Context invokationContext) {
- if (typeUsage instanceof ReferenceTypeUsageImpl) {
- return solveMethodAsUsage((ReferenceTypeUsageImpl) typeUsage, name, parameterTypes, typeSolver, invokationContext);
+ if (typeUsage instanceof ReferenceTypeUsage) {
+ return solveMethodAsUsage((ReferenceTypeUsage) typeUsage, name, parameterTypes, typeSolver, invokationContext);
} else if (typeUsage instanceof TypeParameterUsage) {
return solveMethodAsUsage((TypeParameterUsage) typeUsage, name, parameterTypes, typeSolver, invokationContext);
+ } else if (typeUsage instanceof WildcardUsage) {
+ WildcardUsage wildcardUsage = (WildcardUsage)typeUsage;
+ if (wildcardUsage.isSuper()) {
+ return solveMethodAsUsage(wildcardUsage.getBoundedType(), name, parameterTypes, typeSolver, invokationContext);
+ } else if (wildcardUsage.isExtends()) {
+ throw new UnsupportedOperationException("extends wildcard");
+ } else {
+ throw new UnsupportedOperationException("unbounded wildcard");
+ }
} else {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("type usage: " + typeUsage.getClass().getCanonicalName());
}
}
diff --git a/java-symbol-solver-core/src/test/java/me/tomassetti/symbolsolver/model/typesystem/WildcardUsageTest.java b/java-symbol-solver-core/src/test/java/me/tomassetti/symbolsolver/model/typesystem/WildcardUsageTest.java
index a1bbee1..ec5c6bb 100644
--- a/java-symbol-solver-core/src/test/java/me/tomassetti/symbolsolver/model/typesystem/WildcardUsageTest.java
+++ b/java-symbol-solver-core/src/test/java/me/tomassetti/symbolsolver/model/typesystem/WildcardUsageTest.java
@@ -8,6 +8,7 @@
import org.junit.Test;
import java.util.Collections;
+import java.util.List;
import static org.junit.Assert.*;
@@ -20,6 +21,7 @@
private TypeSolver typeSolver;
private ReferenceTypeUsageImpl foo;
private ReferenceTypeUsageImpl bar;
+ private ReferenceTypeUsageImpl object;
private ReferenceTypeUsageImpl string;
private WildcardUsage unbounded = WildcardUsage.UNBOUNDED;
private WildcardUsage superFoo;
@@ -37,6 +39,7 @@
typeSolver = new JreTypeSolver();
foo = new ReferenceTypeUsageImpl(new ReflectionClassDeclaration(Foo.class, typeSolver), typeSolver);
bar = new ReferenceTypeUsageImpl(new ReflectionClassDeclaration(Bar.class, typeSolver), typeSolver);
+ object = new ReferenceTypeUsageImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver);
string = new ReferenceTypeUsageImpl(new ReflectionClassDeclaration(String.class, typeSolver), typeSolver);
superFoo = WildcardUsage.superBound(foo);
superBar = WildcardUsage.superBound(bar);
@@ -169,25 +172,18 @@
assertTrue(extendsA == extendsA.replaceParam("B", string));
}
- /*@Test
+ @Test
public void testIsAssignableBySimple() {
- assertEquals(true, object.isAssignableBy(string));
- assertEquals(false, string.isAssignableBy(object));
- assertEquals(false, listOfStrings.isAssignableBy(listOfA));
- assertEquals(false, listOfA.isAssignableBy(listOfStrings));
-
- assertEquals(false, object.isAssignableBy(VoidTypeUsage.INSTANCE));
- assertEquals(false, string.isAssignableBy(VoidTypeUsage.INSTANCE));
- assertEquals(false, listOfStrings.isAssignableBy(VoidTypeUsage.INSTANCE));
- assertEquals(false, listOfA.isAssignableBy(VoidTypeUsage.INSTANCE));
-
- assertEquals(true, object.isAssignableBy(NullTypeUsage.INSTANCE));
- assertEquals(true, string.isAssignableBy(NullTypeUsage.INSTANCE));
- assertEquals(true, listOfStrings.isAssignableBy(NullTypeUsage.INSTANCE));
- assertEquals(true, listOfA.isAssignableBy(NullTypeUsage.INSTANCE));
+ assertEquals(false, unbounded.isAssignableBy(object));
+ assertEquals(true, object.isAssignableBy(unbounded));
+ assertEquals(false, string.isAssignableBy(unbounded));
+ assertEquals(true, superFoo.isAssignableBy(foo));
+ assertEquals(false, foo.isAssignableBy(superFoo));
+ assertEquals(false, extendsFoo.isAssignableBy(foo));
+ assertEquals(true, foo.isAssignableBy(extendsFoo));
}
- @Test
+ /*@Test
public void testIsAssignableByGenerics() {
assertEquals(false, listOfStrings.isAssignableBy(listOfWildcardExtendsString));
assertEquals(false, listOfStrings.isAssignableBy(listOfWildcardExtendsString));
diff --git a/java-symbol-solver-examples/pom.xml b/java-symbol-solver-examples/pom.xml
index b2af5be..f0ff30b 100644
--- a/java-symbol-solver-examples/pom.xml
+++ b/java-symbol-solver-examples/pom.xml
@@ -56,7 +56,12 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
- </dependency>
+ </dependency>
+ <dependency>
+ <groupId>me.tomassetti</groupId>
+ <artifactId>java-symbol-solver-core</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/java-symbol-solver-examples/src/main/java/me/tomassetti/examples/PrintExpressionType.java b/java-symbol-solver-examples/src/main/java/me/tomassetti/examples/PrintExpressionType.java
new file mode 100644
index 0000000..f68c7a6
--- /dev/null
+++ b/java-symbol-solver-examples/src/main/java/me/tomassetti/examples/PrintExpressionType.java
@@ -0,0 +1,4 @@
+package me.tomassetti.examples;
+
+public class PrintExpressionType {
+}
diff --git a/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Address.java b/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Address.java
new file mode 100644
index 0000000..2037d14
--- /dev/null
+++ b/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Address.java
@@ -0,0 +1,42 @@
+package someproject.me.tomassetti;
+
+public class Address {
+ private String street;
+ private int number;
+ private String city;
+ private int zipCode;
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public int getZipCode() {
+ return zipCode;
+ }
+
+ public void setZipCode(int zipCode) {
+ this.zipCode = zipCode;
+ }
+
+
+}
diff --git a/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Agenda.java b/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Agenda.java
new file mode 100644
index 0000000..4c8664c
--- /dev/null
+++ b/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Agenda.java
@@ -0,0 +1,22 @@
+package someproject.me.tomassetti;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Agenda {
+
+ private List<Person> persons = new ArrayList<>();
+
+ public void addPerson(Person person) {
+ persons.add(person);
+ }
+
+ public List<Address> findAddressesOfPersons(String personName) {
+ return persons.stream().
+ filter(p -> p.getName().equals(personName)).
+ map(p -> p.getAddress()).
+ collect(Collectors.toList());
+ }
+
+}
diff --git a/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Person.java b/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Person.java
new file mode 100644
index 0000000..98b014d
--- /dev/null
+++ b/java-symbol-solver-examples/src/main/resources/someproject/me/tomassetti/Person.java
@@ -0,0 +1,24 @@
+package someproject.me.tomassetti;
+
+public class Person {
+
+ private String name;
+ private Address address;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+
+ public String getName() {
+ return name;
+
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+}
\ No newline at end of file