forked from JavaTX/JavaCompilerCore
Test generics
This commit is contained in:
parent
9f27d0d0fa
commit
f3e7fc0dc3
@ -31,6 +31,7 @@ import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
|||||||
import de.dhbwstuttgart.syntaxtree.type.TypeVisitor;
|
import de.dhbwstuttgart.syntaxtree.type.TypeVisitor;
|
||||||
import de.dhbwstuttgart.syntaxtree.visual.ASTTypePrinter;
|
import de.dhbwstuttgart.syntaxtree.visual.ASTTypePrinter;
|
||||||
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
|
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
|
||||||
|
import de.dhbwstuttgart.target.generate.GenericsResult;
|
||||||
import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
||||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||||
@ -852,10 +853,10 @@ public class JavaTXCompiler {
|
|||||||
generateBytecode(path, typeinferenceResult);
|
generateBytecode(path, typeinferenceResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<File, List<ASTToTargetAST.GenericsResult>> generatedGenerics = new HashMap<>();
|
private Map<File, List<GenericsResult>> generatedGenerics = new HashMap<>();
|
||||||
|
|
||||||
// TODO This is a temporary solution, we should integrate with the old API for getting Generics
|
// TODO This is a temporary solution, we should integrate with the old API for getting Generics
|
||||||
public Map<File, List<ASTToTargetAST.GenericsResult>> getGeneratedGenerics() {
|
public Map<File, List<GenericsResult>> getGeneratedGenerics() {
|
||||||
return generatedGenerics;
|
return generatedGenerics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package de.dhbwstuttgart.syntaxtree.type;
|
package de.dhbwstuttgart.syntaxtree.type;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
import de.dhbwstuttgart.syntaxtree.ASTVisitor;
|
import de.dhbwstuttgart.syntaxtree.ASTVisitor;
|
||||||
import de.dhbwstuttgart.syntaxtree.SyntaxTreeNode;
|
import de.dhbwstuttgart.syntaxtree.SyntaxTreeNode;
|
||||||
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
|
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
|
||||||
@ -47,6 +48,10 @@ public class TypePlaceholder extends RefTypeOrTPHOrWildcardOrGeneric
|
|||||||
return new TypePlaceholder(NameGenerator.makeNewName(), position);
|
return new TypePlaceholder(NameGenerator.makeNewName(), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RefTypeOrTPHOrWildcardOrGeneric of(String name) {
|
||||||
|
return new TypePlaceholder(name, new NullToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Author: J�rg B�uerle<br/>
|
* Author: J�rg B�uerle<br/>
|
||||||
|
@ -20,122 +20,17 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
public class ASTToTargetAST {
|
public class ASTToTargetAST {
|
||||||
|
|
||||||
static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change
|
public static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change
|
||||||
|
|
||||||
protected List<Sigma> all;
|
protected List<Sigma> all;
|
||||||
protected Sigma sigma;
|
protected Sigma sigma;
|
||||||
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's
|
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's
|
||||||
|
|
||||||
private record Bound(boolean isOnMethod, RefTypeOrTPHOrWildcardOrGeneric bound) {}
|
|
||||||
|
|
||||||
private static boolean boundChainEquals(List<Bound> left, List<Bound> right) {
|
|
||||||
if (left.size() != right.size()) return false;
|
|
||||||
for (var i = 0; i < left.size(); i++) {
|
|
||||||
var l = left.get(i);
|
|
||||||
var r = right.get(i);
|
|
||||||
if (l.isOnMethod != r.isOnMethod) return false;
|
|
||||||
if (i == left.size() - 1) {
|
|
||||||
if (!(l.bound instanceof TypePlaceholder)) {
|
|
||||||
if (!(l.bound.equals(r.bound))) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class GenericsResult {
|
|
||||||
|
|
||||||
final Map<ClassOrInterface, Set<ResultPair<?, ?>>> computedGenericsOfClasses;
|
|
||||||
final Map<Method, Set<ResultPair<?, ?>>> computedGenericsOfMethods;
|
|
||||||
|
|
||||||
final Sigma sigma;
|
|
||||||
|
|
||||||
public GenericsResult(
|
|
||||||
Map<ClassOrInterface, Set<ResultPair<?, ?>>> computedGenericsOfClasses,
|
|
||||||
Map<Method, Set<ResultPair<?, ?>>> computedGenericsOfMethods) {
|
|
||||||
this.computedGenericsOfMethods = computedGenericsOfMethods;
|
|
||||||
this.computedGenericsOfClasses = computedGenericsOfClasses;
|
|
||||||
this.sigma = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private GenericsResult(Sigma sigma) {
|
|
||||||
this.computedGenericsOfMethods = sigma.computedGenericsOfMethods;
|
|
||||||
this.computedGenericsOfClasses = sigma.computedGenericsOfClasses;
|
|
||||||
this.sigma = sigma;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<ResultPair<?, ?>> get(ClassOrInterface clazz) {
|
|
||||||
return computedGenericsOfClasses.get(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<ResultPair<?, ?>> get(Method method) {
|
|
||||||
return computedGenericsOfMethods.get(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypePlaceholder equality(TypePlaceholder tph) {
|
|
||||||
if (this.sigma == null) return tph;
|
|
||||||
else return this.sigma.equality.getOrDefault(tph, tph);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Bound> boundChain(ClassOrInterface clazz, Method method, TypePlaceholder tph) {
|
|
||||||
var result = new ArrayList<Bound>();
|
|
||||||
|
|
||||||
RefTypeOrTPHOrWildcardOrGeneric bound = equality(tph);
|
|
||||||
var constraintsForMethod = get(method);
|
|
||||||
var constraintsForClass = get(clazz);
|
|
||||||
Optional<ResultPair<?, ?>> newBound;
|
|
||||||
do {
|
|
||||||
RefTypeOrTPHOrWildcardOrGeneric finalBound1 = bound;
|
|
||||||
newBound = constraintsForMethod.stream().filter(pair -> pair.getLeft().equals(finalBound1)).findFirst();
|
|
||||||
if (newBound.isPresent()) {
|
|
||||||
bound = newBound.get().getRight();
|
|
||||||
result.add(new Bound(true, bound));
|
|
||||||
} else {
|
|
||||||
RefTypeOrTPHOrWildcardOrGeneric finalBound = bound;
|
|
||||||
newBound = constraintsForClass.stream().filter(pair -> pair.getLeft().equals(finalBound)).findFirst();
|
|
||||||
if (newBound.isPresent()) {
|
|
||||||
bound = newBound.get().getRight();
|
|
||||||
result.add(new Bound(false, bound));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (newBound.isPresent());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof GenericsResult other)) return false;
|
|
||||||
if (this.computedGenericsOfClasses.size() != other.computedGenericsOfClasses.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (var clazz : this.computedGenericsOfClasses.keySet()) {
|
|
||||||
if (!other.computedGenericsOfClasses.containsKey(clazz)) return false;
|
|
||||||
|
|
||||||
for (var method : clazz.getMethods()) {
|
|
||||||
for (var param : method.getParameterList()) {
|
|
||||||
if (param.getType() instanceof TypePlaceholder tph) {
|
|
||||||
var leftBound = boundChain(clazz, method, tph);
|
|
||||||
var rightBound = other.boundChain(clazz, method, tph);
|
|
||||||
if (!boundChainEquals(leftBound, rightBound)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (method.getReturnType() instanceof TypePlaceholder tph) {
|
|
||||||
var leftBound = boundChain(clazz, method, tph);
|
|
||||||
var rightBound = other.boundChain(clazz, method, tph);
|
|
||||||
if (!boundChainEquals(leftBound, rightBound)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<GenericsResult> computedGenerics() {
|
public List<GenericsResult> computedGenerics() {
|
||||||
return all.stream().map(GenericsResult::new).toList();
|
return all.stream().map(GenericsResult::new).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Sigma {
|
class Sigma {
|
||||||
Map<Method, Set<ResultPair<?, ?>>> computedGenericsOfMethods = new HashMap<>();
|
Map<Method, Set<ResultPair<?, ?>>> computedGenericsOfMethods = new HashMap<>();
|
||||||
Map<Method, Set<TypePlaceholder>> usedTPHsOfMethods = new HashMap<>();
|
Map<Method, Set<TypePlaceholder>> usedTPHsOfMethods = new HashMap<>();
|
||||||
Map<ClassOrInterface, Set<ResultPair<?, ?>>> computedGenericsOfClasses = new HashMap<>();
|
Map<ClassOrInterface, Set<ResultPair<?, ?>>> computedGenericsOfClasses = new HashMap<>();
|
||||||
@ -366,8 +261,9 @@ public class ASTToTargetAST {
|
|||||||
if (pair.right.equals(pair2.left))
|
if (pair.right.equals(pair2.left))
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
if (!hasBound(pair.right, genericsOfClass) && typeVariables.contains(pair.right))
|
if (!hasBound(pair.right, genericsOfClass) && typeVariables.contains(pair.right)) {
|
||||||
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eliminateCyclesAndInfima(result);
|
eliminateCyclesAndInfima(result);
|
||||||
@ -489,8 +385,8 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void eliminateCyclesAndInfima(Set<ResultPair<?, ?>> input) {
|
|
||||||
// Eliminate cycles
|
void eliminateCycles(Set<ResultPair<?, ?>> input) {
|
||||||
var cycles = findCycles(input);
|
var cycles = findCycles(input);
|
||||||
for (var cycle : cycles) {
|
for (var cycle : cycles) {
|
||||||
var newTph = TypePlaceholder.fresh(new NullToken());
|
var newTph = TypePlaceholder.fresh(new NullToken());
|
||||||
@ -504,7 +400,9 @@ public class ASTToTargetAST {
|
|||||||
equality.put(left, newTph);
|
equality.put(left, newTph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Eliminate infima
|
}
|
||||||
|
|
||||||
|
void eliminateInfima(Set<ResultPair<?, ?>> input) {
|
||||||
var foundInfima = false;
|
var foundInfima = false;
|
||||||
do {
|
do {
|
||||||
foundInfima = false;
|
foundInfima = false;
|
||||||
@ -546,9 +444,21 @@ public class ASTToTargetAST {
|
|||||||
} while (foundInfima);
|
} while (foundInfima);
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetType get(TypePlaceholder tph) {
|
void eliminateCyclesAndInfima(Set<ResultPair<?, ?>> input) {
|
||||||
|
eliminateCycles(input);
|
||||||
|
eliminateInfima(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
RefTypeOrTPHOrWildcardOrGeneric getType(TypePlaceholder tph) {
|
||||||
if (equality.containsKey(tph)) {
|
if (equality.containsKey(tph)) {
|
||||||
return get(equality.get(tph));
|
return getType(equality.get(tph));
|
||||||
|
}
|
||||||
|
return concreteTypes.getOrDefault(tph, tph);
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetType getTargetType(TypePlaceholder tph) {
|
||||||
|
if (equality.containsKey(tph)) {
|
||||||
|
return getTargetType(equality.get(tph));
|
||||||
}
|
}
|
||||||
var type = concreteTypes.get(tph);
|
var type = concreteTypes.get(tph);
|
||||||
if (type == null) return new TargetGenericType(tph.getName());
|
if (type == null) return new TargetGenericType(tph.getName());
|
||||||
@ -818,7 +728,7 @@ public class ASTToTargetAST {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TargetType visit(TypePlaceholder typePlaceholder) {
|
public TargetType visit(TypePlaceholder typePlaceholder) {
|
||||||
return sigma.get(typePlaceholder);
|
return sigma.getTargetType(typePlaceholder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
24
src/main/java/de/dhbwstuttgart/target/generate/Bound.java
Normal file
24
src/main/java/de/dhbwstuttgart/target/generate/Bound.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package de.dhbwstuttgart.target.generate;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record Bound(boolean isOnMethod, RefTypeOrTPHOrWildcardOrGeneric bound) {
|
||||||
|
|
||||||
|
public static boolean chainEquals(List<Bound> left, List<Bound> right) {
|
||||||
|
if (left.size() != right.size()) return false;
|
||||||
|
for (var i = 0; i < left.size(); i++) {
|
||||||
|
var l = left.get(i);
|
||||||
|
var r = right.get(i);
|
||||||
|
if (l.isOnMethod != r.isOnMethod) return false;
|
||||||
|
if (i == left.size() - 1) {
|
||||||
|
if (!(l.bound instanceof TypePlaceholder)) {
|
||||||
|
if (!(l.bound.equals(r.bound))) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package de.dhbwstuttgart.target.generate;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.Method;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||||
|
import de.dhbwstuttgart.typeinference.result.ResultPair;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class GenericsResult {
|
||||||
|
final ASTToTargetAST.Sigma sigma;
|
||||||
|
|
||||||
|
public GenericsResult(ASTToTargetAST.Sigma sigma) {
|
||||||
|
this.sigma = sigma;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ResultPair<?, ?>> get(ClassOrInterface clazz) {
|
||||||
|
return this.sigma.computedGenericsOfClasses.getOrDefault(clazz, Set.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ResultPair<?, ?>> get(Method method) {
|
||||||
|
return this.sigma.computedGenericsOfMethods.getOrDefault(method, Set.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Bound> getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz) {
|
||||||
|
return getBounds(type, clazz, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Bound> getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz, Method method) {
|
||||||
|
type = resolve(type);
|
||||||
|
if (type instanceof TypePlaceholder) {
|
||||||
|
var methodGenerics = get(method);
|
||||||
|
var classGenerics = get(clazz);
|
||||||
|
List<Bound> result = new ArrayList<>();
|
||||||
|
|
||||||
|
Optional<Bound> bound = Optional.empty();
|
||||||
|
do {
|
||||||
|
bound = Optional.empty();
|
||||||
|
for (var pair : methodGenerics) {
|
||||||
|
if (pair.getLeft().equals(type)) {
|
||||||
|
type = resolve(pair.getRight());
|
||||||
|
bound = Optional.of(new Bound(true, type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bound.isEmpty()) {
|
||||||
|
for (var pair : classGenerics) {
|
||||||
|
if (pair.getLeft().equals(type)) {
|
||||||
|
type = resolve(pair.getRight());
|
||||||
|
bound = Optional.of(new Bound(false, type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bound.ifPresent(result::add);
|
||||||
|
} while (bound.isPresent());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RefTypeOrTPHOrWildcardOrGeneric resolve(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||||
|
if (type instanceof TypePlaceholder tph)
|
||||||
|
return this.sigma.getType(tph);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
@ -2,33 +2,363 @@ package targetast;
|
|||||||
|
|
||||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||||
import de.dhbwstuttgart.target.generate.ASTToTargetAST.GenericsResult;
|
import de.dhbwstuttgart.syntaxtree.Field;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.Method;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||||
|
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
|
||||||
|
import de.dhbwstuttgart.target.generate.Bound;
|
||||||
|
import de.dhbwstuttgart.target.generate.GenericsResult;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.SocketHandler;
|
||||||
|
|
||||||
|
|
||||||
public class TestGenerics {
|
public class TestGenerics {
|
||||||
|
|
||||||
private static final String rootDirectory = System.getProperty("user.dir") + "/src/test/resources/insertGenericsJav/";
|
private static final String rootDirectory = System.getProperty("user.dir") + "/src/test/resources/insertGenericsJav/";
|
||||||
|
private static final String bytecodeDirectory = System.getProperty("user.dir") + "/src/test/resources/testBytecode/generatedBC/";
|
||||||
|
|
||||||
private record Result(List<GenericsResult> genericsResults, ClassOrInterface clazz) {}
|
private record Result(List<GenericsResult> genericsResults, ClassOrInterface clazz) {
|
||||||
|
Method findMethod(String name) {
|
||||||
|
return clazz.getMethods().stream().filter(m -> m.getName().equals(name)).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Field findField(String name) {
|
||||||
|
return clazz.getFieldDecl().stream().filter(field -> field.getName().equals(name)).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Result computeGenerics(String filename) throws IOException, ClassNotFoundException {
|
private static Result computeGenerics(String filename) throws IOException, ClassNotFoundException {
|
||||||
var file = Path.of(rootDirectory + filename).toFile();
|
var file = Path.of(rootDirectory + filename).toFile();
|
||||||
var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()));
|
var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()));
|
||||||
var inference = compiler.typeInference();
|
var inference = compiler.typeInference();
|
||||||
compiler.generateBytecode(null, inference);
|
compiler.generateBytecode(new File(bytecodeDirectory), inference);
|
||||||
var clazz = compiler.sourceFiles.get(file).getClasses().get(0);
|
var clazz = compiler.sourceFiles.get(file).getClasses().get(0);
|
||||||
return new Result(compiler.getGeneratedGenerics().get(file), clazz);
|
return new Result(compiler.getGeneratedGenerics().get(file), clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAny() throws Exception {
|
public void testAny() throws Exception {
|
||||||
var generics = computeGenerics("TestAny.jav");
|
var result = computeGenerics("TestAny.jav");
|
||||||
for (var result : generics.genericsResults) {
|
var anyMethod = result.findMethod("anyMethod");
|
||||||
System.out.println(result.get(generics.clazz));
|
var otherMethod = result.findMethod("otherMethod");
|
||||||
}
|
var a = result.findField("a");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
assertEquals(1, generics.get(anyMethod).size());
|
||||||
|
assertEquals(2, generics.get(result.clazz).size());
|
||||||
|
|
||||||
|
var ECK1 = generics.getBounds(otherMethod.getParameterList().getParameterAt(0).getType(), result.clazz, anyMethod);
|
||||||
|
var ECK2 = generics.getBounds(otherMethod.getReturnType(), result.clazz, anyMethod);
|
||||||
|
var ECKChain = List.of(new Bound(false, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(ECK1, ECK2) && Bound.chainEquals(ECK2, ECKChain));
|
||||||
|
|
||||||
|
var M = generics.getBounds(a.getType(), result.clazz);
|
||||||
|
var MChain = List.of(new Bound(false, TypePlaceholder.of("ECK")), new Bound(false, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(M, MChain));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClassField() throws Exception {
|
||||||
|
var result = computeGenerics("TestClassField.jav");
|
||||||
|
var fReturn = result.findMethod("fReturn");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
assertEquals(1, generics.get(result.clazz).size());
|
||||||
|
assertEquals(0, generics.get(fReturn).size());
|
||||||
|
|
||||||
|
var N = generics.getBounds(fReturn.getReturnType(), result.clazz);
|
||||||
|
var NChain = List.of(new Bound(false, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(N, NChain));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContraVariant() throws Exception {
|
||||||
|
var result = computeGenerics("TestContraVariant.jav");
|
||||||
|
var m = result.findMethod("m");
|
||||||
|
var main = result.findMethod("main");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
assertEquals(0, generics.get(result.clazz).size());
|
||||||
|
assertEquals(2, generics.get(m).size());
|
||||||
|
assertEquals(2, generics.get(main).size());
|
||||||
|
|
||||||
|
var N = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m);
|
||||||
|
var NChain = List.of(new Bound(true, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(N, NChain));
|
||||||
|
|
||||||
|
var Q = generics.getBounds(m.getReturnType(), result.clazz, m);
|
||||||
|
var QChain = List.of(new Bound(true, TypePlaceholder.of("N")), new Bound(true, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(Q, QChain));
|
||||||
|
|
||||||
|
var R = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
|
||||||
|
assertTrue(Bound.chainEquals(R, NChain));
|
||||||
|
|
||||||
|
var Q2 = generics.getBounds(main.getReturnType(), result.clazz, main);
|
||||||
|
assertTrue(Bound.chainEquals(Q2, NChain));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGGFinder() throws Exception {
|
||||||
|
var result = computeGenerics("TestGGFinder.jav");
|
||||||
|
var id = result.findMethod("id");
|
||||||
|
var setA = result.findMethod("setA");
|
||||||
|
var m = result.findMethod("m");
|
||||||
|
var a = result.findField("a");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
assertEquals(1, generics.get(result.clazz).size());
|
||||||
|
assertEquals(2, generics.get(id).size());
|
||||||
|
assertEquals(1, generics.get(setA).size());
|
||||||
|
assertEquals(2, generics.get(m).size());
|
||||||
|
|
||||||
|
var R = generics.getBounds(a.getType(), result.clazz);
|
||||||
|
var RChain = List.of(new Bound(false, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(R, RChain));
|
||||||
|
|
||||||
|
var O = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id);
|
||||||
|
var OChain = List.of(new Bound(true, TypePlaceholder.of("AB")), new Bound(true, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(O, OChain));
|
||||||
|
var AB = generics.getBounds(id.getReturnType(), result.clazz, id);
|
||||||
|
assertTrue(Bound.chainEquals(AB, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
|
||||||
|
var S = generics.getBounds(setA.getParameterList().getParameterAt(0).getType(), result.clazz, setA);
|
||||||
|
var SChain = List.of(new Bound(true, TypePlaceholder.of("R")), new Bound(false, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(S, SChain));
|
||||||
|
assertTrue(Bound.chainEquals(generics.getBounds(setA.getReturnType(), result.clazz, setA), RChain));
|
||||||
|
|
||||||
|
var X = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m);
|
||||||
|
var Y = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m);
|
||||||
|
var XChain = List.of(new Bound(true, ASTToTargetAST.OBJECT));
|
||||||
|
var YChain = List.of(new Bound(true, TypePlaceholder.of("Y")), new Bound(true, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(X, XChain));
|
||||||
|
assertTrue(Bound.chainEquals(Y, YChain));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore("Not implemented")
|
||||||
|
public void testLocalVarLambda() throws Exception {
|
||||||
|
var result = computeGenerics("TestLocalVarLambda.jav");
|
||||||
|
// TODO Generics of lambdas
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMutualRecursion() throws Exception {
|
||||||
|
var result = computeGenerics("TestMutualRecursion.jav");
|
||||||
|
var id = result.findMethod("id");
|
||||||
|
var m = result.findMethod("m");
|
||||||
|
var main = result.findMethod("main");
|
||||||
|
var a = result.findField("a");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
assertEquals(1, generics.get(result.clazz).size());
|
||||||
|
assertEquals(3, generics.get(id).size());
|
||||||
|
assertEquals(2, generics.get(m).size());
|
||||||
|
assertEquals(3, generics.get(main).size());
|
||||||
|
|
||||||
|
var M = generics.getBounds(a.getType(), result.clazz);
|
||||||
|
assertTrue(Bound.chainEquals(M, List.of(new Bound(false, ASTToTargetAST.OBJECT))));
|
||||||
|
|
||||||
|
var O = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id);
|
||||||
|
var OChain = List.of(new Bound(true, TypePlaceholder.of("P")), new Bound(true, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(O, OChain));
|
||||||
|
var AK = generics.getBounds(id.getReturnType(), result.clazz, id);
|
||||||
|
var AKChain = List.of(new Bound(true, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(AK, AKChain));
|
||||||
|
|
||||||
|
// TODO Shouldn't AK and AK2 be the same and on the class?
|
||||||
|
var AK2 = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m);
|
||||||
|
var Y = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m);
|
||||||
|
assertTrue(Bound.chainEquals(AK2, AKChain));
|
||||||
|
assertTrue(Bound.chainEquals(Y, AKChain));
|
||||||
|
|
||||||
|
var AF = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
|
||||||
|
var AG= generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main);
|
||||||
|
var AK3 = generics.getBounds(main.getReturnType(), result.clazz, main);
|
||||||
|
var AFChain = List.of(new Bound(true, TypePlaceholder.of("AG")), new Bound(true, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(AF, AFChain));
|
||||||
|
assertTrue(Bound.chainEquals(AG, AKChain));
|
||||||
|
assertTrue(Bound.chainEquals(AK3, AKChain));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReturnVar() throws Exception {
|
||||||
|
var result = computeGenerics("TestReturnVar.jav");
|
||||||
|
var anyMethod = result.findMethod("anyMethod");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
assertEquals(1, generics.get(anyMethod).size());
|
||||||
|
|
||||||
|
var M = generics.getBounds(anyMethod.getReturnType(), result.clazz, anyMethod);
|
||||||
|
assertTrue(Bound.chainEquals(M, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecondLineOfClassConstraints() throws Exception {
|
||||||
|
var result = computeGenerics("TestSecondLineOfClassConstraints.jav");
|
||||||
|
var a = result.findField("a");
|
||||||
|
var b = result.findField("b");
|
||||||
|
var anyMethod = result.findMethod("anyMethod");
|
||||||
|
var otherMethod = result.findMethod("otherMethod");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
var M = generics.getBounds(a.getType(), result.clazz);
|
||||||
|
var DYX = generics.getBounds(b.getType(), result.clazz);
|
||||||
|
var MChain = List.of(new Bound(false, TypePlaceholder.of("DYX")), new Bound(false, ASTToTargetAST.OBJECT));
|
||||||
|
var DYXChain = List.of(new Bound(false, ASTToTargetAST.OBJECT));
|
||||||
|
assertTrue(Bound.chainEquals(M, MChain));
|
||||||
|
|
||||||
|
var Q = generics.getBounds(anyMethod.getReturnType(), result.clazz, anyMethod);
|
||||||
|
assertTrue(Bound.chainEquals(Q, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
|
||||||
|
var DYX2 = generics.getBounds(otherMethod.getReturnType(), result.clazz, otherMethod);
|
||||||
|
assertTrue(Bound.chainEquals(DYX, DYX2) && Bound.chainEquals(DYX2, DYXChain));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore("This doesn't work properly")
|
||||||
|
public void testThreeArgs() throws Exception {
|
||||||
|
var result = computeGenerics("TestThreeArgs.jav");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTPHsAndGenerics() throws Exception {
|
||||||
|
var result = computeGenerics("TestTPHsAndGenerics.jav");
|
||||||
|
var id2 = result.findMethod("id2");
|
||||||
|
var m = result.findMethod("m");
|
||||||
|
var m2 = result.findMethod("m2");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
var U = generics.getBounds(id2.getParameterList().getParameterAt(0).getType(), result.clazz, id2);
|
||||||
|
var FPT = generics.getBounds(id2.getReturnType(), result.clazz, id2);
|
||||||
|
assertTrue(Bound.chainEquals(U, List.of(new Bound(true, TypePlaceholder.of("FPT")), new Bound(false, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(FPT, List.of(new Bound(false, ASTToTargetAST.OBJECT))));
|
||||||
|
|
||||||
|
var AA = generics.getBounds(m.getReturnType(), result.clazz, m);
|
||||||
|
var AC = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m);
|
||||||
|
assertTrue(Bound.chainEquals(AA, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(AC, List.of(new Bound(true, TypePlaceholder.of("AD")), new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
|
||||||
|
var AH = generics.getBounds(m2.getReturnType(), result.clazz, m2);
|
||||||
|
var AL = generics.getBounds(m2.getParameterList().getParameterAt(0).getType(), result.clazz, m2);
|
||||||
|
assertTrue(Bound.chainEquals(AH, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(AH, AL));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTwoArgs() throws Exception {
|
||||||
|
var result = computeGenerics("TestTwoArgs.jav");
|
||||||
|
|
||||||
|
var a = result.findField("a");
|
||||||
|
var id = result.findMethod("id");
|
||||||
|
var setA = result.findMethod("setA");
|
||||||
|
var m = result.findMethod("m");
|
||||||
|
var main = result.findMethod("main");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
var AO = generics.getBounds(a.getType(), result.clazz);
|
||||||
|
var AOBound = List.of(
|
||||||
|
new Bound(false, TypePlaceholder.of("Y")),
|
||||||
|
new Bound(false, TypePlaceholder.of("AK")),
|
||||||
|
new Bound(false, TypePlaceholder.of("AE")),
|
||||||
|
new Bound(false, ASTToTargetAST.OBJECT)
|
||||||
|
);
|
||||||
|
assertTrue(Bound.chainEquals(AO, AOBound));
|
||||||
|
|
||||||
|
var S = generics.getBounds(setA.getParameterList().getParameterAt(0).getType(), result.clazz, setA);
|
||||||
|
var SChain = new ArrayList<Bound>();
|
||||||
|
SChain.add(new Bound(true, TypePlaceholder.of("AO")));
|
||||||
|
SChain.addAll(AOBound);
|
||||||
|
assertTrue(Bound.chainEquals(S, SChain));
|
||||||
|
|
||||||
|
var Y = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m);
|
||||||
|
var YChain = List.of(new Bound(true, TypePlaceholder.of("AE")), new Bound(false, ASTToTargetAST.OBJECT));
|
||||||
|
var AE = generics.getBounds(m.getReturnType(), result.clazz, m);
|
||||||
|
assertTrue(Bound.chainEquals(Y, YChain));
|
||||||
|
assertTrue(Bound.chainEquals(AE, List.of(new Bound(false, ASTToTargetAST.OBJECT))));
|
||||||
|
|
||||||
|
// TODO main seems to change between runs
|
||||||
|
/*var AE2 = generics.getBounds(main.getReturnType(), result.clazz, main);
|
||||||
|
var AF = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
|
||||||
|
var AG = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main);
|
||||||
|
assertTrue(Bound.chainEquals(AE, AE2));
|
||||||
|
assertTrue(Bound.chainEquals(AF, List.of(new Bound(true, TypePlaceholder.of("AK")), new Bound(true, TypePlaceholder.of("AE")), new Bound(false, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(AG, SChain));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore("main changes in between runs")
|
||||||
|
public void testTwoArgs2() throws Exception {
|
||||||
|
var result = computeGenerics("TestTwoArgs2.jav");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTwoCalls() throws Exception {
|
||||||
|
var result = computeGenerics("TestTwoCalls.jav");
|
||||||
|
var id = result.findMethod("id");
|
||||||
|
var main = result.findMethod("main");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
var Q = generics.getBounds(id.getReturnType(), result.clazz, id);
|
||||||
|
var N = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id);
|
||||||
|
assertTrue(Bound.chainEquals(Q, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(N, List.of(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
|
||||||
|
var Q2 = generics.getBounds(main.getReturnType(), result.clazz, main);
|
||||||
|
var R = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
|
||||||
|
var S = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main);
|
||||||
|
assertTrue(Bound.chainEquals(Q2, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(R, List.of(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(S, List.of(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVector() throws Exception {
|
||||||
|
var result = computeGenerics("TestVector.jav");
|
||||||
|
var m = result.findMethod("m");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
var par1 = generics.resolve(m.getParameterList().getParameterAt(0).getType());
|
||||||
|
var par2 = generics.resolve(m.getParameterList().getParameterAt(1).getType());
|
||||||
|
|
||||||
|
var S = generics.getBounds(((RefType) par1).getParaList().get(0), result.clazz, m);
|
||||||
|
var ACM = generics.getBounds(((RefType) par2).getParaList().get(0), result.clazz, m);
|
||||||
|
assertTrue(Bound.chainEquals(S, List.of(new Bound(true, TypePlaceholder.of("V")), new Bound(true, TypePlaceholder.of("ACM")), new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(ACM, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVectorArg() throws Exception {
|
||||||
|
var result = computeGenerics("TestVectorArg.jav");
|
||||||
|
var add = result.findMethod("add");
|
||||||
|
var main = result.findMethod("main");
|
||||||
|
|
||||||
|
var generics = result.genericsResults.get(0);
|
||||||
|
var par1 = generics.resolve(add.getParameterList().getParameterAt(0).getType());
|
||||||
|
var ACK = generics.getBounds(((RefType) par1).getParaList().get(0), result.clazz, add);
|
||||||
|
var O = generics.getBounds(add.getParameterList().getParameterAt(1).getType(), result.clazz, add);
|
||||||
|
assertTrue(Bound.chainEquals(ACK, List.of(new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
assertTrue(Bound.chainEquals(O, List.of(new Bound(true, TypePlaceholder.of("ACK")), new Bound(true, ASTToTargetAST.OBJECT))));
|
||||||
|
|
||||||
|
var par2 = generics.resolve(main.getParameterList().getParameterAt(0).getType());
|
||||||
|
var ACK2 = generics.getBounds(((RefType) par2).getParaList().get(0), result.clazz, add);
|
||||||
|
var V = generics.getBounds(add.getParameterList().getParameterAt(1).getType(), result.clazz, add);
|
||||||
|
assertTrue(Bound.chainEquals(ACK2, ACK));
|
||||||
|
assertTrue(Bound.chainEquals(V, O));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVoidMeth() throws Exception {
|
||||||
|
var result = computeGenerics("TestVoidMeth.jav");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user