Skip to content

Commit

Permalink
inheriting type parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
ftomassetti committed Oct 31, 2015
1 parent 1a159a6 commit 49f82c8
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 53 deletions.
Expand Up @@ -12,6 +12,7 @@
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.stmt.Statement;
import me.tomassetti.symbolsolver.model.typesystem.ReferenceTypeUsage;
import me.tomassetti.symbolsolver.resolution.TypeSolver;
import me.tomassetti.symbolsolver.model.declarations.TypeDeclaration;

Expand Down Expand Up @@ -78,7 +79,7 @@ private void solveTypeDecl(ClassOrInterfaceDeclaration node) {
TypeDeclaration typeDeclaration = JavaParserFacade.get(typeSolver).getTypeDeclaration(node);
if (typeDeclaration.isClass()) {
out.println("\n[ Class "+ typeDeclaration.getQualifiedName() + " ]");
for (TypeDeclaration sc : typeDeclaration.asClass().getAllSuperClasses(typeSolver)) {
for (ReferenceTypeUsage sc : typeDeclaration.asClass().getAllSuperClasses(typeSolver)) {
out.println(" superclass: " + sc.getQualifiedName());
}
for (TypeDeclaration sc : typeDeclaration.asClass().getAllInterfaces(typeSolver)) {
Expand Down
@@ -1,5 +1,6 @@
package me.tomassetti.symbolsolver.model.declarations;

import me.tomassetti.symbolsolver.model.typesystem.ReferenceTypeUsage;
import me.tomassetti.symbolsolver.resolution.TypeSolver;

import java.util.ArrayList;
Expand All @@ -15,24 +16,24 @@ default boolean isClass() {
return true;
}

ClassDeclaration getSuperClass(TypeSolver typeSolvers);
ReferenceTypeUsage getSuperClass(TypeSolver typeSolvers);
List<InterfaceDeclaration> getInterfaces(TypeSolver typeSolver);

default List<ClassDeclaration> getAllSuperClasses(TypeSolver typeSolver) {
default List<ReferenceTypeUsage> getAllSuperClasses(TypeSolver typeSolver) {
// TODO it could specify type parameters: they should appear
List<ClassDeclaration> superclasses = new ArrayList<>();
ClassDeclaration superClass = getSuperClass(typeSolver);
List<ReferenceTypeUsage> superclasses = new ArrayList<>();
ReferenceTypeUsage superClass = getSuperClass(typeSolver);
if (superClass != null) {
superclasses.add(superClass);
superclasses.addAll(superClass.getAllSuperClasses(typeSolver));
superclasses.addAll(superClass.getAllAncestors());
}
return superclasses;
}

default List<InterfaceDeclaration> getAllInterfaces(TypeSolver typeSolver) {
// TODO it could specify type parameters: they should appear
List<InterfaceDeclaration> interfaces = new ArrayList<>();
ClassDeclaration superClass = getSuperClass(typeSolver);
//ClassDeclaration superClass = getSuperClass(typeSolver);
for (InterfaceDeclaration interfaceDeclaration : getInterfaces(typeSolver)){
interfaces.add(interfaceDeclaration);
interfaces.addAll(interfaceDeclaration.getAllInterfacesExtended(typeSolver));
Expand Down
@@ -1,5 +1,6 @@
package me.tomassetti.symbolsolver.model.typesystem;

import com.github.javaparser.ast.type.WildcardType;
import me.tomassetti.symbolsolver.resolution.*;
import me.tomassetti.symbolsolver.model.declarations.MethodDeclaration;
import me.tomassetti.symbolsolver.model.declarations.TypeDeclaration;
Expand All @@ -8,6 +9,7 @@
import me.tomassetti.symbolsolver.resolution.reflection.ReflectionClassDeclaration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
Expand Down Expand Up @@ -181,8 +183,11 @@ public TypeUsage replaceParam(String name, TypeUsage replaced) {
}

public List<ReferenceTypeUsage> getAllAncestors() {
List<ReferenceTypeUsage> ancestors = typeDeclaration.getAllAncestors();

ancestors = ancestors.stream().map((a)->replaceTypeParams(a).asReferenceTypeUsage()).collect(Collectors.toList());
// TODO replace type parameters
return typeDeclaration.getAllAncestors();
return ancestors;
}

public TypeUsage replaceTypeParams(TypeUsage typeUsage){
Expand Down Expand Up @@ -268,11 +273,11 @@ public boolean isAssignableBy(TypeUsage other) {
return this.getQualifiedName().equals(Predicate.class.getCanonicalName()) || this.getQualifiedName().equals(Function.class.getCanonicalName());
} else if (other instanceof ReferenceTypeUsage) {
ReferenceTypeUsage otherRef = (ReferenceTypeUsage) other;
if (this.equals(otherRef)) {
if (compareConsideringTypeParameters(otherRef)) {
return true;
}
for (ReferenceTypeUsage otherAncestor : otherRef.getAllAncestors()) {
if (otherAncestor.equals(this)) {
if (compareConsideringTypeParameters(otherAncestor)) {
return true;
}
}
Expand All @@ -285,6 +290,37 @@ public boolean isAssignableBy(TypeUsage other) {
}
}

private boolean compareConsideringTypeParameters(ReferenceTypeUsage other) {
if (other.equals(this)) {
return true;
}
if (this.getQualifiedName().equals(other.getQualifiedName())){
if (this.parameters().size() != other.parameters().size()) {
throw new IllegalStateException();
}
for (int i=0;i<parameters().size();i++) {
TypeUsage thisParam = parameters().get(i);
TypeUsage otherParam = other.parameters().get(i);
if (!thisParam.equals(otherParam)) {
if (thisParam instanceof WildcardUsage) {
WildcardUsage thisParamAsWildcard = (WildcardUsage)thisParam;
if (thisParamAsWildcard.isSuper() && thisParamAsWildcard.getBoundedType().equals(otherParam)) {
// ok
} else if (thisParamAsWildcard.isExtends() && thisParamAsWildcard.getBoundedType().isAssignableBy(otherParam)) {
// ok
} else {
return false;
}
} else {
return false;
}
}
}
return true;
}
return false;
}

private boolean isCorrespondingBoxingType(String typeName) {
switch (typeName) {
case "boolean":
Expand Down
Expand Up @@ -63,6 +63,21 @@ public String describe() {
}
}

public boolean isSuper() {
return type == BoundType.SUPER;
}

public boolean isExtends() {
return type == BoundType.EXTENDS;
}

public ReferenceTypeUsage getBoundedType() {
if (boundedType == null) {
throw new IllegalStateException();
}
return boundedType;
}

@Override
public boolean isAssignableBy(TypeUsage other) {
throw new UnsupportedOperationException();
Expand Down
Expand Up @@ -98,15 +98,15 @@ public boolean isClass() {
}

@Override
public ClassDeclaration getSuperClass(TypeSolver typeSolver) {
public ReferenceTypeUsage getSuperClass(TypeSolver typeSolver) {
if (wrappedNode.getExtends() == null || wrappedNode.getExtends().isEmpty()) {
return typeSolver.getRoot().solveType("java.lang.Object").asType().asClass();
return new ReferenceTypeUsage(typeSolver.getRoot().solveType("java.lang.Object").asType().asClass(), typeSolver);
} else {
SymbolReference<TypeDeclaration> ref = solveType(wrappedNode.getExtends().get(0).getName(), typeSolver);
if (!ref.isSolved()) {
throw new UnsolvedSymbolException(wrappedNode.getExtends().get(0).getName());
}
return ref.getCorrespondingDeclaration().asClass();
return new ReferenceTypeUsage(ref.getCorrespondingDeclaration().asClass(), typeSolver);
}
}

Expand Down Expand Up @@ -199,7 +199,7 @@ public boolean canBeAssignedTo(TypeDeclaration other) {
if (this.getQualifiedName().equals(other.getQualifiedName())) {
return true;
}
ClassDeclaration superclass = getSuperClass(typeSolver);
ClassDeclaration superclass = (ClassDeclaration) getSuperClass(typeSolver).getTypeDeclaration();
if (superclass != null) {
if (superclass.canBeAssignedTo(other)) {
return true;
Expand Down Expand Up @@ -236,7 +236,7 @@ public FieldDeclaration getField(String name) {
}
}

ClassDeclaration superclass = this.getSuperClass(typeSolver);
ClassDeclaration superclass = (ClassDeclaration) this.getSuperClass(typeSolver).getTypeDeclaration();
if (superclass != null) {
return superclass.getField(name);
} else {
Expand Down Expand Up @@ -265,7 +265,7 @@ public boolean hasField(String name) {
}
}

ClassDeclaration superclass = this.getSuperClass(typeSolver);
ClassDeclaration superclass = (ClassDeclaration) this.getSuperClass(typeSolver).getTypeDeclaration();
if (superclass != null) {
return superclass.hasField(name);
} else {
Expand Down Expand Up @@ -329,9 +329,9 @@ public SymbolReference<TypeDeclaration> solveType(String name, TypeSolver typeSo
@Override
public List<ReferenceTypeUsage> getAllAncestors() {
List<ReferenceTypeUsage> ancestors = new ArrayList<>();
ClassDeclaration superclass = getSuperClass(typeSolver);
ReferenceTypeUsage superclass = getSuperClass(typeSolver);
if (superclass != null) {
ancestors.add(new ReferenceTypeUsage(superclass, typeSolver));
ancestors.add(superclass);
ancestors.addAll(superclass.getAllAncestors());
}
if (wrappedNode.getImplements() != null) {
Expand Down
Expand Up @@ -186,7 +186,7 @@ public SymbolReference<TypeDeclaration> solveType(String substring, TypeSolver t
public List<ReferenceTypeUsage> getAllAncestors() {
List<ReferenceTypeUsage> ancestors = new LinkedList<>();
if (getSuperClass(typeSolver) != null) {
ancestors.add(new ReferenceTypeUsage(getSuperClass(typeSolver), typeSolver));
ancestors.add(getSuperClass(typeSolver));
ancestors.addAll(getSuperClass(typeSolver).getAllAncestors());
}
ancestors.addAll(getAllInterfaces(typeSolver).stream().map((i)->new ReferenceTypeUsage(i, typeSolver)).collect(Collectors.<ReferenceTypeUsage>toList()));
Expand Down Expand Up @@ -318,12 +318,12 @@ public boolean isClass() {
}

@Override
public ClassDeclaration getSuperClass(TypeSolver typeSolvers) {
public ReferenceTypeUsage getSuperClass(TypeSolver typeSolvers) {
try {
if (ctClass.getSuperclass() == null) {
throw new UnsupportedOperationException();
}
return new JavassistClassDeclaration(ctClass.getSuperclass(), typeSolver).asClass();
return new ReferenceTypeUsage(new JavassistClassDeclaration(ctClass.getSuperclass(), typeSolver).asClass(), typeSolver);
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
Expand Down
Expand Up @@ -9,10 +9,7 @@
import me.tomassetti.symbolsolver.resolution.javaparser.UnsolvedSymbolException;
import me.tomassetti.symbolsolver.model.typesystem.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.*;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
Expand All @@ -28,7 +25,8 @@ public class ReflectionClassDeclaration implements ClassDeclaration {
public List<ReferenceTypeUsage> getAllAncestors() {
List<ReferenceTypeUsage> ancestors = new LinkedList<>();
if (getSuperClass(typeSolver) != null) {
ancestors.add(new ReferenceTypeUsage(getSuperClass(typeSolver), typeSolver));
ReferenceTypeUsage superClass = getSuperClass(typeSolver);
ancestors.add(superClass);
ancestors.addAll(getSuperClass(typeSolver).getAllAncestors());
}
ancestors.addAll(getAllInterfaces(typeSolver).stream().map((i)->new ReferenceTypeUsage(i, typeSolver)).collect(Collectors.<ReferenceTypeUsage>toList()));
Expand Down Expand Up @@ -133,8 +131,8 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<TypeUsag
MethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver);
methods.add(methodDeclaration);
}
ClassDeclaration superClass = getSuperClass(typeSolver);
if (superClass != null) {
if (getSuperClass(typeSolver) != null) {
ClassDeclaration superClass = (ClassDeclaration)getSuperClass(typeSolver).getTypeDeclaration();
SymbolReference<MethodDeclaration> ref = superClass.solveMethod(name, parameterTypes, typeSolver);
if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration());
Expand Down Expand Up @@ -175,8 +173,8 @@ public Optional<MethodUsage> solveMethodAsUsage(String name, List<TypeUsage> par
}
methods.add(methodUsage);
}
ClassDeclaration superClass = getSuperClass(typeSolver);
if (superClass != null) {
if (getSuperClass(typeSolver) != null) {
ClassDeclaration superClass = (ClassDeclaration)getSuperClass(typeSolver).getTypeDeclaration();
Optional<MethodUsage> ref = superClass.solveMethodAsUsage(name, parameterTypes, typeSolver, invokationContext, typeParameterValues);
if (ref.isPresent()) {
methods.add(ref.get());
Expand Down Expand Up @@ -306,11 +304,11 @@ public boolean hasField(String name) {
return true;
}
}
ClassDeclaration superclass = getSuperClass(typeSolver);
ReferenceTypeUsage superclass = getSuperClass(typeSolver);
if (superclass == null) {
return false;
} else {
return superclass.hasField(name);
return superclass.getTypeDeclaration().hasField(name);
}
}

Expand Down Expand Up @@ -350,16 +348,25 @@ public boolean isClass() {
}

@Override
public ClassDeclaration getSuperClass(TypeSolver typeSolvers) {
if (clazz.getSuperclass() == null) {
public ReferenceTypeUsage getSuperClass(TypeSolver typeSolvers) {
if (clazz.getGenericSuperclass() == null) {
return null;
}
return new ReflectionClassDeclaration(clazz.getSuperclass(), typeSolver);
Type superType = clazz.getGenericSuperclass();
if (superType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)superType;
List<TypeUsage> typeParameters = Arrays.stream(parameterizedType.getActualTypeArguments())
.map((t) -> ReflectionFactory.typeUsageFor(t, typeSolver))
.collect(Collectors.toList());
return new ReferenceTypeUsage(new ReflectionClassDeclaration(clazz.getSuperclass(), typeSolver), typeParameters, typeSolvers);
}
return new ReferenceTypeUsage(new ReflectionClassDeclaration(clazz.getSuperclass(), typeSolver), typeSolvers);
}

@Override
public List<InterfaceDeclaration> getInterfaces(TypeSolver typeSolver) {
List<InterfaceDeclaration> interfaces = new ArrayList<>();
// TODO use genericInterfaces
for (Class i : clazz.getInterfaces()) {
interfaces.add(new ReflectionInterfaceDeclaration(i, typeSolver));
}
Expand Down
Expand Up @@ -212,6 +212,7 @@ class MoreBazzing<A, B> extends Bazzer<B, String, A> {
public void testGetAllAncestorsConsideringGenericsCases() {
ReferenceTypeUsage foo = new ReferenceTypeUsage(new ReflectionClassDeclaration(Foo.class, typeSolver), typeSolver);
ReferenceTypeUsage bar = new ReferenceTypeUsage(new ReflectionClassDeclaration(Bar.class, typeSolver), typeSolver);
ReferenceTypeUsage left, right;

//YES MoreBazzing<Foo, Bar> e1 = new MoreBazzing<Foo, Bar>();
assertEquals(true,
Expand Down Expand Up @@ -254,24 +255,22 @@ public void testGetAllAncestorsConsideringGenericsCases() {
);

//YES MoreBazzing<? extends Foo, ? extends Foo> e5 = new MoreBazzing<Bar, Bar>();
assertEquals(true,
new ReferenceTypeUsage(
new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
ImmutableList.of(WildcardUsage.extendsBound(foo), WildcardUsage.extendsBound(foo)), typeSolver)
.isAssignableBy(new ReferenceTypeUsage(
new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
ImmutableList.of(bar, bar), typeSolver))
);
left = new ReferenceTypeUsage(
new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
ImmutableList.of(WildcardUsage.extendsBound(foo), WildcardUsage.extendsBound(foo)), typeSolver);
right = new ReferenceTypeUsage(
new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
ImmutableList.of(bar, bar), typeSolver);
assertEquals(true, left.isAssignableBy(right));

//YES Bazzer<Object, String, String> e6 = new MoreBazzing<String, Object>();
assertEquals(true,
new ReferenceTypeUsage(
new ReflectionClassDeclaration(Bazzer.class, typeSolver),
ImmutableList.of(object, string, string), typeSolver)
.isAssignableBy(new ReferenceTypeUsage(
new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
ImmutableList.of(string, object), typeSolver))
);
left = new ReferenceTypeUsage(
new ReflectionClassDeclaration(Bazzer.class, typeSolver),
ImmutableList.of(object, string, string), typeSolver);
right = new ReferenceTypeUsage(
new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
ImmutableList.of(string, object), typeSolver);
assertEquals(true, left.isAssignableBy(right));

//YES Bazzer<String,String,String> e7 = new MoreBazzing<String, String>();
assertEquals(true,
Expand Down
Expand Up @@ -271,7 +271,8 @@ public void typeParamOnReturnTypeStep3() throws ParseException {
MethodDeclaration method = Navigator.demandMethod(clazz, "nodeEquals");
MethodCallExpr call = Navigator.findMethodCall(method, "accept");

TypeUsage typeUsage = JavaParserFacade.get(new JreTypeSolver()).getType(call);
JavaParserFacade javaParserFacade = JavaParserFacade.get(new JreTypeSolver());
TypeUsage typeUsage = javaParserFacade.getType(call);

assertEquals(false, typeUsage.isTypeVariable());
assertEquals("java.lang.Boolean", typeUsage.describe());
Expand Down
Expand Up @@ -3,6 +3,7 @@
import com.github.javaparser.ParseException;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import me.tomassetti.symbolsolver.model.typesystem.ReferenceTypeUsage;
import me.tomassetti.symbolsolver.resolution.javaparser.JavaParserFacade;
import me.tomassetti.symbolsolver.javaparser.Navigator;
import me.tomassetti.symbolsolver.model.declarations.TypeDeclaration;
Expand All @@ -21,7 +22,7 @@ public void typeDeclarationSuperClassImplicitlyIncludeObject() throws ParseExcep
CompilationUnit cu = parseSample("Generics");
ClassOrInterfaceDeclaration clazz = Navigator.demandClass(cu, "Generics");
TypeDeclaration typeDeclaration = JavaParserFacade.get(new JreTypeSolver()).getTypeDeclaration(clazz);
TypeDeclaration superclass = typeDeclaration.asClass().getSuperClass(new JreTypeSolver());
ReferenceTypeUsage superclass = typeDeclaration.asClass().getSuperClass(new JreTypeSolver());
assertEquals(Object.class.getCanonicalName(), superclass.getQualifiedName());
}
}

0 comments on commit 49f82c8

Please sign in to comment.