Compare commits

...

8 Commits

Author SHA1 Message Date
Victorious3
904bdca2f4 Eliminate transitive children, add missing object bounds 2023-04-25 15:06:56 +02:00
Victorious3
af4db1817a Add test and fix up the generics a bit 2023-04-19 19:08:52 +02:00
Victorious3
d945947362 ASM doesn't like empty generics for some reason, don't know if valid? 2023-04-19 16:12:24 +02:00
Victorious3
a0c25a517d Use old method of creating signatures in case the classloader is null 2023-04-19 15:33:53 +02:00
Victorious3
c35577f948 Add missing functions and test the signature parser 2023-04-19 14:56:59 +02:00
Victorious3
fc7844c6a4 Merge branch 'targetBytecode' into parseSignature 2023-04-14 15:18:36 +02:00
Victorious3
4078239815 - Calculate veriance for new type variables in Infima & Cycles
- Remove referenced check from Infima
- Correctly identify contra & covariance for chains for tphs
2023-04-14 15:04:26 +02:00
Victorious3
39bde24df7 Start working on signature parsing 2023-04-14 11:38:41 +02:00
17 changed files with 579 additions and 99 deletions

@@ -0,0 +1,11 @@
import java.lang.String;
class TXGenerics {
a;
b;
test() {
var c = new Cycle();
c.m(a, b);
}
}

@@ -5,7 +5,7 @@ public class TestContraVariant {
x = y; x = y;
return y; return y;
} }
main(x) { main(x) {
return m(x); return m(x);
} }

@@ -1,10 +1,12 @@
public class TestTwoCalls { public class TestTwoCalls {
// <O> O -> O
id(b) { id(b) {
var c = b; var c = b;
return c; return c;
} }
// <T, S> (S, T) -> T
main(x,y) { main(x,y) {
id(x); id(x);
return id(y); return id(y);

@@ -1000,7 +1000,7 @@ public class Codegen {
private void generateConstructor(TargetConstructor constructor) { private void generateConstructor(TargetConstructor constructor) {
MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "<init>", constructor.getDescriptor(), constructor.getSignature(), null); MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "<init>", constructor.getDescriptor(), constructor.getSignature(), null);
if (constructor.txGenerics() != null) if (constructor.txGenerics() != null)
mv.visitAttribute(new JavaTXSignatureAttribute(cw.newConst(constructor.getTXSignature()))); mv.visitAttribute(new JavaTXSignatureAttribute(constructor.getTXSignature()));
mv.visitCode(); mv.visitCode();
var state = new State(null, mv, 1); var state = new State(null, mv, 1);
@@ -1027,7 +1027,7 @@ public class Codegen {
// TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else // TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else
MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null); MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null);
if (method.txSignature() != null) { if (method.txSignature() != null) {
mv.visitAttribute(new JavaTXSignatureAttribute(cw.newConst(method.getTXSignature()))); mv.visitAttribute(new JavaTXSignatureAttribute(method.getTXSignature()));
} }
System.out.println(method.getDescriptor()); System.out.println(method.getDescriptor());
@@ -1044,11 +1044,14 @@ public class Codegen {
} }
private static String generateSignature(TargetClass clazz, Set<TargetGeneric> generics) { private static String generateSignature(TargetClass clazz, Set<TargetGeneric> generics) {
String ret = "<"; String ret = "";
for (var generic : generics) { if (generics.size() > 0) {
ret += generic.name() + ":" + generic.bound().toDescriptor(); ret += "<";
for (var generic : generics) {
ret += generic.name() + ":" + generic.bound().toDescriptor();
}
ret += ">";
} }
ret += ">";
ret += clazz.superType().toDescriptor(); ret += clazz.superType().toDescriptor();
return ret; return ret;
@@ -1060,7 +1063,7 @@ public class Codegen {
clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new) clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)
); );
if (clazz.txGenerics() != null) if (clazz.txGenerics() != null)
cw.visitAttribute(new JavaTXSignatureAttribute(cw.newConst(generateSignature(clazz, clazz.txGenerics())))); cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics())));
clazz.fields().forEach(this::generateField); clazz.fields().forEach(this::generateField);
clazz.constructors().forEach(this::generateConstructor); clazz.constructors().forEach(this::generateConstructor);

@@ -3,10 +3,13 @@ package de.dhbwstuttgart.bytecode;
import org.objectweb.asm.*; import org.objectweb.asm.*;
public class JavaTXSignatureAttribute extends Attribute { public class JavaTXSignatureAttribute extends Attribute {
final int signature; public String signature;
protected JavaTXSignatureAttribute(int signature) { public JavaTXSignatureAttribute() {
super("JavaTXSignature"); super("JavaTXSignature");
}
protected JavaTXSignatureAttribute(String signature) {
this();
this.signature = signature; this.signature = signature;
} }
@@ -14,13 +17,14 @@ public class JavaTXSignatureAttribute extends Attribute {
protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) { protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) {
var data = new byte[length]; var data = new byte[length];
System.arraycopy(classReader.b, offset, data, 0, length); System.arraycopy(classReader.b, offset, data, 0, length);
return new JavaTXSignatureAttribute(data[0] << 8 | data[1]); var constantPoolOffset = data[0] << 8 | data[1];
return new JavaTXSignatureAttribute((String) classReader.readConst(constantPoolOffset, charBuffer));
} }
@Override @Override
protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) { protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) {
var data = new ByteVector(); var data = new ByteVector();
data.putShort(this.signature); data.putShort(classWriter.newConst(this.signature));
return data; return data;
} }
} }

@@ -49,4 +49,17 @@ public class GenericDeclarationList extends SyntaxTreeNode implements Iterable<G
public String toString() { public String toString() {
return this.gtvs.toString(); return this.gtvs.toString();
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GenericDeclarationList that = (GenericDeclarationList) o;
return gtvs.equals(that.gtvs);
}
@Override
public int hashCode() {
return Objects.hash(gtvs);
}
} }

@@ -6,6 +6,7 @@ import org.antlr.v4.runtime.Token;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Entspricht einem GenericTypeVar, jedoch mit Bounds * Entspricht einem GenericTypeVar, jedoch mit Bounds
@@ -45,7 +46,7 @@ public class GenericTypeVar extends SyntaxTreeNode
public String toString() public String toString()
{ {
return "BoGTV " + this.name; return "BoGTV " + this.name + " " + this.bounds;
} }
public String getName(){ public String getName(){
@@ -61,4 +62,17 @@ public class GenericTypeVar extends SyntaxTreeNode
public void accept(ASTVisitor visitor) { public void accept(ASTVisitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GenericTypeVar that = (GenericTypeVar) o;
return bounds.equals(that.bounds) && name.equals(that.name);
}
@Override
public int hashCode() {
return Objects.hash(bounds, name);
}
} }

@@ -1,19 +1,16 @@
package de.dhbwstuttgart.syntaxtree.factory; package de.dhbwstuttgart.syntaxtree.factory;
import java.io.IOException;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.ArrayList; import java.lang.reflect.Type;
import java.util.Arrays; import java.nio.file.Files;
import java.util.HashSet; import java.nio.file.Path;
import java.util.List; import java.util.*;
import java.util.Optional;
import java.util.Set;
import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.bytecode.JavaTXSignatureAttribute;
import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.GenericContext;
import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
import de.dhbwstuttgart.syntaxtree.Field; import de.dhbwstuttgart.syntaxtree.Field;
import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.type.*; import de.dhbwstuttgart.syntaxtree.type.*;
@@ -22,7 +19,14 @@ import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.Block; import de.dhbwstuttgart.syntaxtree.statement.Block;
import de.dhbwstuttgart.syntaxtree.statement.Statement; import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.type.WildcardType; import de.dhbwstuttgart.syntaxtree.type.WildcardType;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.util.Pair;
import javassist.bytecode.SignatureAttribute;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import org.apache.commons.io.IOUtils;
import org.objectweb.asm.*;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
/** /**
* Anmerkung: * Anmerkung:
@@ -32,21 +36,76 @@ import org.antlr.v4.runtime.Token;
public class ASTFactory { public class ASTFactory {
public static ClassOrInterface createClass(java.lang.Class jreClass){ public static ClassOrInterface createClass(java.lang.Class jreClass){
// TODO Inner classes
var methodSignatures = new HashMap<Pair<String, String>, String>();
String classSignature = null;
// Load class with asm to figure out if there's a JavaTX signature
try {
var path = jreClass.getName().replace('.', '/') + ".class";
var classLoader = jreClass.getClassLoader();
if (classLoader != null) {
var bytes = IOUtils.toByteArray(Objects.requireNonNull(classLoader.getResourceAsStream(path)));
var classReader = new ClassReader(bytes);
var classVisitor = new ClassVisitor(Opcodes.ASM7) {
String classSignature;
@Override
public void visitAttribute(Attribute attribute) {
if (attribute.type.equals("JavaTXSignature")) {
classSignature = ((JavaTXSignatureAttribute) attribute).signature;
}
super.visitAttribute(attribute);
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
classSignature = signature;
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
methodSignatures.put(new Pair<>(name, descriptor), signature);
return new MethodVisitor(Opcodes.ASM7) {
@Override
public void visitAttribute(Attribute attribute) {
if (attribute.type.equals("JavaTXSignature")) {
methodSignatures.put(new Pair<>(name, descriptor), ((JavaTXSignatureAttribute) attribute).signature);
}
super.visitAttribute(attribute);
}
};
}
};
classReader.accept(classVisitor, new Attribute[]{new JavaTXSignatureAttribute()}, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
classSignature = classVisitor.classSignature;
}
} catch (IOException e) {
// Skip
}
JavaClassName name = new JavaClassName(jreClass.getName()); JavaClassName name = new JavaClassName(jreClass.getName());
List<Method> methoden = new ArrayList<>(); List<Method> methoden = new ArrayList<>();
List<de.dhbwstuttgart.syntaxtree.Constructor> konstruktoren = new ArrayList<>(); List<de.dhbwstuttgart.syntaxtree.Constructor> konstruktoren = new ArrayList<>();
for(java.lang.reflect.Constructor constructor : jreClass.getConstructors()){ for(java.lang.reflect.Constructor constructor : jreClass.getConstructors()){
createConstructor(constructor, jreClass).map(c -> konstruktoren.add(c)); var signature = methodSignatures.get(new Pair<>(constructor.getName(), org.objectweb.asm.Type.getConstructorDescriptor(constructor)));
createConstructor(constructor, signature, jreClass).map(c -> konstruktoren.add(c));
} }
Set<java.lang.reflect.Method> allMethods = new HashSet<>(Arrays.asList(jreClass.getMethods())); Set<java.lang.reflect.Method> allMethods = new HashSet<>(Arrays.asList(jreClass.getMethods()));
Set<java.lang.reflect.Method> allDeclaredMethods = new HashSet<>(Arrays.asList(jreClass.getDeclaredMethods())); Set<java.lang.reflect.Method> allDeclaredMethods = new HashSet<>(Arrays.asList(jreClass.getDeclaredMethods()));
Set<java.lang.reflect.Method> allInheritedMethods = new HashSet<>(allMethods); Set<java.lang.reflect.Method> allInheritedMethods = new HashSet<>(allMethods);
allInheritedMethods.removeAll(allDeclaredMethods); allInheritedMethods.removeAll(allDeclaredMethods);
for(java.lang.reflect.Method method : allDeclaredMethods){ for(java.lang.reflect.Method method : allDeclaredMethods){
methoden.add(createMethod(method, jreClass, false)); var signature = methodSignatures.get(new Pair<>(method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method)));
methoden.add(createMethod(method, signature, jreClass, false));
} }
for(java.lang.reflect.Method method : allInheritedMethods){ for(java.lang.reflect.Method method : allInheritedMethods){
methoden.add(createMethod(method, jreClass, true)); var signature = methodSignatures.get(new Pair<>(method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method)));
methoden.add(createMethod(method, signature, jreClass, true));
} }
List<Field> felder = new ArrayList<>(); List<Field> felder = new ArrayList<>();
for(java.lang.reflect.Field field : jreClass.getDeclaredFields()){ for(java.lang.reflect.Field field : jreClass.getDeclaredFields()){
@@ -72,7 +131,8 @@ public class ASTFactory {
for(Type jreInterface : jreClass.getGenericInterfaces()){ for(Type jreInterface : jreClass.getGenericInterfaces()){
implementedInterfaces.add((RefType) createType(jreInterface)); implementedInterfaces.add((RefType) createType(jreInterface));
} }
GenericDeclarationList genericDeclarationList = createGenerics(jreClass.getTypeParameters(), jreClass, null);
GenericDeclarationList genericDeclarationList = createGenerics(jreClass.getTypeParameters(), jreClass, null, classSignature);
Token offset = new NullToken(); //Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde Token offset = new NullToken(); //Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde
@@ -87,7 +147,7 @@ public class ASTFactory {
// return createClass(classType).getType(); // return createClass(classType).getType();
//} //}
private static Optional<de.dhbwstuttgart.syntaxtree.Constructor> createConstructor(Constructor constructor, Class inClass) { private static Optional<de.dhbwstuttgart.syntaxtree.Constructor> createConstructor(Constructor constructor, String signature, Class inClass) {
String name = constructor.getName(); String name = constructor.getName();
RefTypeOrTPHOrWildcardOrGeneric returnType = createType(inClass); RefTypeOrTPHOrWildcardOrGeneric returnType = createType(inClass);
Parameter[] jreParams = constructor.getParameters(); Parameter[] jreParams = constructor.getParameters();
@@ -101,7 +161,7 @@ public class ASTFactory {
} }
ParameterList parameterList = new ParameterList(params, new NullToken()); ParameterList parameterList = new ParameterList(params, new NullToken());
Block block = new Block(new ArrayList<Statement>(), new NullToken()); Block block = new Block(new ArrayList<Statement>(), new NullToken());
GenericDeclarationList gtvDeclarations = createGenerics(constructor.getTypeParameters(), inClass, constructor.getName()); GenericDeclarationList gtvDeclarations = createGenerics(constructor.getTypeParameters(), inClass, constructor.getName(), signature);
Token offset = new NullToken(); Token offset = new NullToken();
int modifier = constructor.getModifiers(); int modifier = constructor.getModifiers();
@@ -112,7 +172,7 @@ public class ASTFactory {
return Optional.of(new de.dhbwstuttgart.syntaxtree.Constructor(modifier, name,returnType, parameterList, block, gtvDeclarations, offset /*, new ArrayList<>() geloescht PL 2018-11-24 */)); return Optional.of(new de.dhbwstuttgart.syntaxtree.Constructor(modifier, name,returnType, parameterList, block, gtvDeclarations, offset /*, new ArrayList<>() geloescht PL 2018-11-24 */));
} }
public static Method createMethod(java.lang.reflect.Method jreMethod, java.lang.Class inClass, Boolean isInherited){ public static Method createMethod(java.lang.reflect.Method jreMethod, String signature, java.lang.Class inClass, Boolean isInherited){
String name = jreMethod.getName(); String name = jreMethod.getName();
RefTypeOrTPHOrWildcardOrGeneric returnType; RefTypeOrTPHOrWildcardOrGeneric returnType;
Type jreRetType; Type jreRetType;
@@ -133,19 +193,142 @@ public class ASTFactory {
} }
ParameterList parameterList = new ParameterList(params, new NullToken()); ParameterList parameterList = new ParameterList(params, new NullToken());
Block block = new Block(new ArrayList<Statement>(), new NullToken()); Block block = new Block(new ArrayList<Statement>(), new NullToken());
GenericDeclarationList gtvDeclarations = createGenerics(jreMethod.getTypeParameters(), inClass, jreMethod.getName()); GenericDeclarationList gtvDeclarations = createGenerics(jreMethod.getTypeParameters(), inClass, jreMethod.getName(), signature);
Token offset = new NullToken(); Token offset = new NullToken();
return new Method(jreMethod.getModifiers(), name,returnType, parameterList, block, gtvDeclarations, offset, isInherited); return new Method(jreMethod.getModifiers(), name,returnType, parameterList, block, gtvDeclarations, offset, isInherited);
} }
public static GenericDeclarationList createGenerics(TypeVariable[] typeParameters, Class context, String methodName){ public static GenericDeclarationList createGenerics(TypeVariable[] typeParameters, Class context, String methodName, String signature) {
List<de.dhbwstuttgart.syntaxtree.GenericTypeVar> gtvs = new ArrayList<>(); if (signature == null) {
for(TypeVariable jreTV : typeParameters){ List<de.dhbwstuttgart.syntaxtree.GenericTypeVar> gtvs = new ArrayList<>();
de.dhbwstuttgart.syntaxtree.GenericTypeVar gtv = createGeneric(jreTV, jreTV.getName(), context, methodName); for(TypeVariable jreTV : typeParameters){
gtvs.add(gtv); de.dhbwstuttgart.syntaxtree.GenericTypeVar gtv = createGeneric(jreTV, jreTV.getName(), context, methodName);
gtvs.add(gtv);
}
return new GenericDeclarationList(gtvs, new NullToken());
} else {
var res = createGenerics(signature);
return res;
} }
return new GenericDeclarationList(gtvs,new NullToken()); }
public static GenericDeclarationList createGenerics(String signature) {
if (signature == null) return new GenericDeclarationList(new ArrayList<>(), new NullToken());
var gtvs = new ArrayList<GenericTypeVar>();
var signatureVisitor = new SignatureVisitor(Opcodes.ASM7) {
List<RefTypeOrTPHOrWildcardOrGeneric> bounds = new ArrayList<>();
final Stack<RefTypeOrTPHOrWildcardOrGeneric> bound = new Stack<>();
final Stack<RefType> classTypes = new Stack<>();
// All hail the mighty visitor pattern
final SignatureVisitor doNothing = new SignatureVisitor(Opcodes.ASM7) {};
char wildcard = '=';
@Override
public SignatureVisitor visitSuperclass() {
return doNothing;
}
@Override
public SignatureVisitor visitParameterType() {
return doNothing;
}
@Override
public SignatureVisitor visitReturnType() {
return doNothing;
}
@Override
public SignatureVisitor visitExceptionType() {
return doNothing;
}
@Override
public void visitFormalTypeParameter(String name) {
bounds = new ArrayList<>();
gtvs.add(new GenericTypeVar(name, bounds, new NullToken(), new NullToken()));
}
@Override
public void visitTypeVariable(String name) {
var refType = new GenericRefType(name, new NullToken());
if (classTypes.isEmpty()) {
((List<RefTypeOrTPHOrWildcardOrGeneric>) gtvs.get(gtvs.size() - 1).getBounds()).add(refType);
} else {
pushType(refType);
}
}
@Override
public void visitClassType(String name) {
var refType = new RefType(new JavaClassName(name.replaceAll("/", ".")), new ArrayList<>(), new NullToken());
classTypes.push(refType);
pushType(refType);
}
void pushType(RefTypeOrTPHOrWildcardOrGeneric refType) {
if (wildcard == SignatureVisitor.SUPER) {
bound.push(new SuperWildcardType(refType, new NullToken()));
} else if (wildcard == SignatureVisitor.EXTENDS) {
bound.push(new ExtendsWildcardType(refType, new NullToken()));
} else {
bound.push(refType);
}
}
@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
this.wildcard = wildcard;
return this;
}
boolean equals(RefTypeOrTPHOrWildcardOrGeneric a, RefTypeOrTPHOrWildcardOrGeneric b) {
if (b instanceof SuperWildcardType wc)
return equals(a, wc.getInnerType());
else if (b instanceof ExtendsWildcardType wc)
return equals(a, wc.getInnerType());
return a == b;
}
@Override
public void visitEnd() {
wildcard = '=';
var classType = (RefType) classTypes.pop();
if (!classTypes.isEmpty()) {
var next = classTypes.peek();
var par = bound.pop();
var toAdd = new ArrayList<RefTypeOrTPHOrWildcardOrGeneric>();
while (!equals(next, par)) {
toAdd.add(par);
par = bound.pop();
}
var element = par;
if (par instanceof WildcardType wc) {
element = wc.getInnerType();
}
Collections.reverse(toAdd);
((RefType) element).getParaList().addAll(toAdd);
bound.push(par);
} else {
if (bound.peek() != classType) {
classType.getParaList().add(bound.pop());
bounds.add(classType);
} else {
bounds.add(bound.pop());
}
}
}
};
var sr = new SignatureReader(signature);
sr.accept(signatureVisitor);
return new GenericDeclarationList(gtvs, new NullToken());
} }
private static RefTypeOrTPHOrWildcardOrGeneric createType(java.lang.reflect.Type type){ private static RefTypeOrTPHOrWildcardOrGeneric createType(java.lang.reflect.Type type){

@@ -5,6 +5,8 @@ import de.dhbwstuttgart.syntaxtree.ASTVisitor;
import de.dhbwstuttgart.typeinference.result.ResultSetVisitor; import de.dhbwstuttgart.typeinference.result.ResultSetVisitor;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import java.util.Objects;
/** /**
* Stellt eine Wildcard mit oberer Grenze dar. * Stellt eine Wildcard mit oberer Grenze dar.
* z.B. void test(? extends Number var){..} * z.B. void test(? extends Number var){..}
@@ -54,9 +56,16 @@ public class ExtendsWildcardType extends WildcardType{
visitor.visit(this); visitor.visit(this);
} }
@Override
public int hashCode() {
return Objects.hashCode(this.innerType);
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
// TODO Auto-generated method stub if (this == o) return true;
return false; if (o == null || getClass() != o.getClass()) return false;
ExtendsWildcardType that = (ExtendsWildcardType) o;
return that.innerType.equals(this.innerType);
} }
} }

@@ -4,6 +4,8 @@ import de.dhbwstuttgart.syntaxtree.ASTVisitor;
import de.dhbwstuttgart.typeinference.result.ResultSetVisitor; import de.dhbwstuttgart.typeinference.result.ResultSetVisitor;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import java.util.Objects;
public class GenericRefType extends RefTypeOrTPHOrWildcardOrGeneric public class GenericRefType extends RefTypeOrTPHOrWildcardOrGeneric
{ {
private String name; private String name;
@@ -33,14 +35,20 @@ public class GenericRefType extends RefTypeOrTPHOrWildcardOrGeneric
visitor.visit(this); visitor.visit(this);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
// TODO Auto-generated method stub if (this == o) return true;
return false; if (o == null || getClass() != o.getClass()) return false;
} GenericRefType that = (GenericRefType) o;
return name.equals(that.name);
}
@Override
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public String toString() public String toString()
{ {
return "GTV " + this.name; return "GTV " + this.name;

@@ -2,9 +2,12 @@ package de.dhbwstuttgart.syntaxtree.type;
import de.dhbwstuttgart.syntaxtree.ASTVisitor; import de.dhbwstuttgart.syntaxtree.ASTVisitor;
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
import de.dhbwstuttgart.typeinference.result.ResultSetVisitor; import de.dhbwstuttgart.typeinference.result.ResultSetVisitor;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import java.util.Objects;
/** /**
* Stellt eine Wildcard mit unterer Grenze dar. * Stellt eine Wildcard mit unterer Grenze dar.
* z.B. void test(? super Integer var){..} * z.B. void test(? super Integer var){..}
@@ -65,9 +68,16 @@ public class SuperWildcardType extends WildcardType{
visitor.visit(this); visitor.visit(this);
} }
@Override
public int hashCode() {
return Objects.hashCode(this.innerType);
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
// TODO Auto-generated method stub if (this == o) return true;
return false; if (o == null || getClass() != o.getClass()) return false;
SuperWildcardType that = (SuperWildcardType) o;
return that.innerType.equals(this.innerType);
} }
} }

@@ -16,8 +16,10 @@ import de.dhbwstuttgart.target.tree.expression.TargetExpression;
import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.constraints.Pair; import de.dhbwstuttgart.typeinference.constraints.Pair;
import de.dhbwstuttgart.typeinference.result.*; import de.dhbwstuttgart.typeinference.result.*;
import org.objectweb.asm.Attribute;
import java.util.*; import java.util.*;
import java.util.concurrent.CyclicBarrier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -170,7 +172,6 @@ public class ASTToTargetAST {
for (var pair : simplifiedConstraints) { for (var pair : simplifiedConstraints) {
if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) { if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) {
addToPairs(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); addToPairs(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right)));
typeVariables.add(pair.right);
} }
} }
} }
@@ -196,7 +197,7 @@ public class ASTToTargetAST {
RefTypeOrTPHOrWildcardOrGeneric T2 = superType; RefTypeOrTPHOrWildcardOrGeneric T2 = superType;
if (T2 instanceof TypePlaceholder tph) T2 = equality.getOrDefault(tph, tph); if (T2 instanceof TypePlaceholder tph) T2 = equality.getOrDefault(tph, tph);
System.out.println("T1s: " + T1s + "\nT2: " + T2); System.out.println("T1s: " + T1s + " T2: " + T2);
//Ende //Ende
superType = methodCall.receiverType; superType = methodCall.receiverType;
@@ -211,7 +212,7 @@ public class ASTToTargetAST {
var optMethod = findMethod(owner, methodCall.name, methodCall.getArgumentList()); var optMethod = findMethod(owner, methodCall.name, methodCall.getArgumentList());
if (optMethod.isEmpty()) return; if (optMethod.isEmpty()) return;
var method = optMethod.get(); var method = optMethod.get();
var generics = generics(owner, method).javaGenerics(); var generics = generics(owner, method).txGenerics();
// transitive and // transitive and
var all = transitiveClosure(generics); var all = transitiveClosure(generics);
@@ -226,24 +227,24 @@ public class ASTToTargetAST {
// Loop from hell // Loop from hell
outer: outer:
for (var tph : typeVariables) { for (var R1 : typeVariables) {
if (typeVariablesOfClass.contains(tph)) continue; if (typeVariablesOfClass.contains(R1)) continue;
for (var generic : all) { for (var generic : all) {
if (!(generic.getRight() instanceof TypePlaceholder type)) if (!(generic.getRight() instanceof TypePlaceholder type))
continue; continue;
for (var pair : simplifiedConstraints) { for (var pair : simplifiedConstraints) {
if (!(pair.left.equals(tph) && pair.right.equals(generic.getLeft()))) if (!(pair.left.equals(R1) && pair.right.equals(generic.getLeft())))
continue; continue;
for (var tph2 : typeVariables) { for (var R2 : typeVariables) {
for (var pair2 : simplifiedConstraints) { for (var pair2 : simplifiedConstraints) {
if (!(pair2.right.equals(tph2) && pair2.left.equals(type))) if (!(pair2.right.equals(R2) && pair2.left.equals(type)))
continue; continue;
if (tph.equals(tph2)) continue; if (R1.equals(R2)) continue;
if (!T1s.contains(tph) || !tph2.equals(T2)) continue; if (!T1s.contains(R1) || !R2.equals(T2)) continue;
var newPair = new PairTPHsmallerTPH(tph, tph2); var newPair = new PairTPHsmallerTPH(R1, R2);
newPairs.add(newPair); newPairs.add(newPair);
if (!containsRelation(result, newPair)) if (!containsRelation(result, newPair))
@@ -268,7 +269,7 @@ public class ASTToTargetAST {
@Override @Override
public void visit(Assign assign) { public void visit(Assign assign) {
superType = assign.lefSide.getType(); superType = assign.rightSide.getType();
assign.rightSide.accept(this); assign.rightSide.accept(this);
} }
@@ -521,9 +522,6 @@ public class ASTToTargetAST {
super.visit(methodCall); super.visit(methodCall);
typeVariables.addAll(findTypeVariables(methodCall.getType(), equality)); typeVariables.addAll(findTypeVariables(methodCall.getType(), equality));
} }
@Override
public void visit(Assign assign) {}
}); });
} }
@@ -554,10 +552,11 @@ public class ASTToTargetAST {
methodFindConstraints(owner, method, simplifiedConstraints, txTypeVariables, classGenerics.userDefinedGenerics, txTypeVariablesOfClass, txResult, txEquality); methodFindConstraints(owner, method, simplifiedConstraints, txTypeVariables, classGenerics.userDefinedGenerics, txTypeVariablesOfClass, txResult, txEquality);
{ // Java Generics { // Java Generics
eliminateTransitives(javaResult);
var referenced = new HashSet<TypePlaceholder>(); var referenced = new HashSet<TypePlaceholder>();
eliminateCycles(javaResult, equality, referenced); eliminateCycles(javaResult, equality, referenced);
eliminateInfima(javaResult, equality, referenced); eliminateInfima(javaResult, equality);
var usedTphs = new HashSet<TypePlaceholder>(); var usedTphs = new HashSet<TypePlaceholder>();
// For eliminating inner type variables we need to figure out which ones are actually used // For eliminating inner type variables we need to figure out which ones are actually used
@@ -571,11 +570,13 @@ public class ASTToTargetAST {
eliminateInnerTypeVariables(referenced, javaResult); eliminateInnerTypeVariables(referenced, javaResult);
equalizeTypeVariables(javaResult, equality); equalizeTypeVariables(javaResult, equality);
usedTPHsOfMethods.put(method, usedTphs); usedTPHsOfMethods.put(method, usedTphs);
addMissingObjectBounds(javaResult, genericsOfClass);
} }
{ {
var referenced = new HashSet<TypePlaceholder>(); var referenced = new HashSet<TypePlaceholder>();
// JavaTX Generics // JavaTX Generics
eliminateInfima(txResult, txEquality, referenced); eliminateTransitives(txResult);
eliminateInfima(txResult, txEquality);
for (var param : method.getParameterList().getFormalparalist()) { for (var param : method.getParameterList().getFormalparalist()) {
referenced.addAll(findTypeVariables(param.getType(), txEquality)); referenced.addAll(findTypeVariables(param.getType(), txEquality));
@@ -584,12 +585,36 @@ public class ASTToTargetAST {
referenced.addAll(txTypeVariablesOfClass); referenced.addAll(txTypeVariablesOfClass);
eliminateInnerTypeVariables(referenced, txResult); eliminateInnerTypeVariables(referenced, txResult);
addMissingObjectBounds(txResult, txGenericsOfClass);
} }
System.out.println(method.name + ": " + txResult + " & " + javaResult); System.out.println(method.name + ": " + txResult + " & " + javaResult);
return generics; return generics;
} }
private void eliminateChain(Set<ResultPair<?, ?>> result, List<TypePlaceholder> chain) {
for (var pair : new HashSet<>(result)) {
if (pair instanceof PairTPHsmallerTPH ptph && chain.get(chain.size() - 1).equals(ptph.left)) {
if (chain.contains(ptph.right)) return;
var copy = new ArrayList<>(chain);
copy.add(ptph.right);
if (copy.size() > 2)
result.remove(new PairTPHsmallerTPH(chain.get(0), ptph.right));
eliminateChain(result, copy);
}
}
}
void eliminateTransitives(Set<ResultPair<?,?>> result) {
for (var pair : new HashSet<>(result)) if (pair instanceof PairTPHsmallerTPH ptph) {
var first = ptph.left;
var chain = new ArrayList<TypePlaceholder>();
chain.add(ptph.left);
chain.add(ptph.right);
eliminateChain(result, chain);
}
}
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<ResultPair<?, ?>> generics, Map<TypePlaceholder, TypePlaceholder> equality) { void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<ResultPair<?, ?>> generics, Map<TypePlaceholder, TypePlaceholder> equality) {
if (type instanceof TypePlaceholder tph) { if (type instanceof TypePlaceholder tph) {
tph = equality.getOrDefault(tph, tph); tph = equality.getOrDefault(tph, tph);
@@ -634,34 +659,86 @@ public class ASTToTargetAST {
findAllBounds(field.getType(), txResult, txEquality); findAllBounds(field.getType(), txResult, txEquality);
} }
eliminateTransitives(javaResult);
eliminateTransitives(txResult);
System.out.println(javaResult);
var referenced = new HashSet<TypePlaceholder>(); var referenced = new HashSet<TypePlaceholder>();
eliminateCycles(javaResult, equality, referenced); eliminateCycles(javaResult, equality, referenced);
eliminateInfima(javaResult, equality, referenced); eliminateInfima(javaResult, equality);
var txReferenced = new HashSet<TypePlaceholder>(); var txReferenced = new HashSet<TypePlaceholder>();
eliminateInfima(txResult, txEquality, txReferenced); eliminateInfima(txResult, txEquality);
eliminateInnerTypeVariablesOfClass(classOrInterface, javaResult, equality, referenced); eliminateInnerTypeVariablesOfClass(classOrInterface, javaResult, equality, referenced);
equalizeTypeVariables(javaResult, equality); equalizeTypeVariables(javaResult, equality);
eliminateInnerTypeVariablesOfClass(classOrInterface, txResult, txEquality, txReferenced); eliminateInnerTypeVariablesOfClass(classOrInterface, txResult, txEquality, txReferenced);
addMissingObjectBounds(javaResult, null);
addMissingObjectBounds(txResult, null);
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + txResult + ", " + javaResult); System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + txResult + ", " + javaResult);
return generics; return generics;
} }
void addMissingObjectBounds(Set<ResultPair<?,?>> result, Set<ResultPair<?, ?>> filter) {
outer: for (var p1 : new HashSet<>(result)) {
if (p1 instanceof PairTPHsmallerTPH ptph) {
for (var p2 : new HashSet<>(result)) {
if (ptph.right.equals(p2.getLeft()))
continue outer;
}
if (filter == null || filter.stream().noneMatch((pair) -> pair.getLeft().equals(ptph.right)))
result.add(new PairTPHequalRefTypeOrWildcardType(ptph.right, OBJECT));
}
}
}
void equalizeTypeVariables(Set<ResultPair<?, ?>> input, Map<TypePlaceholder, TypePlaceholder> equality) { void equalizeTypeVariables(Set<ResultPair<?, ?>> input, Map<TypePlaceholder, TypePlaceholder> equality) {
System.out.println(input);
for (var pair : new HashSet<>(input)) { for (var pair : new HashSet<>(input)) {
if (pair instanceof PairTPHsmallerTPH ptph) { if (pair instanceof PairTPHsmallerTPH ptph) {
System.out.println(pair + " " + ptph.left.getVariance() + " " + ptph.right.getVariance()); var chain = new ArrayList<TypePlaceholder>();
if (ptph.left.getVariance() == 1 && ptph.right.getVariance() == -1) { chain.add(ptph.left);
addToEquality(equality, ptph.left, ptph.right); chain.add(ptph.right);
input.remove(ptph);
for (var pair2 : new HashSet<>(simplifiedConstraints)) { outer: while (true) {
if (pair2.right.equals(ptph.left)) { var added = false;
simplifiedConstraints.remove(pair2); for (var pair2 : input) {
simplifiedConstraints.add(new PairTPHsmallerTPH(pair2.left, ptph.right)); if (pair2 instanceof PairTPHsmallerTPH ptph2 && ptph2.left.equals(chain.get(chain.size() - 1))) {
if (chain.contains(ptph2.right)) break outer;
chain.add(ptph2.right);
added = true;
} }
} }
if (!added) break;
}
var variance = chain.get(0).getVariance();
if (variance != 1) continue;
var index = 0;
for (var tph : chain) {
if (variance == 1 && tph.getVariance() == -1) {
variance = -1;
}
if (variance == -1 && tph.getVariance() == 1) {
break;
}
index++;
}
if (variance == 1) continue;
var start = chain.get(0);
var prev = start;
for (var i = 1; i < index; i++) {
var cur = chain.get(i);
addToEquality(equality, cur, start);
input.remove(new PairTPHsmallerTPH(prev, chain.get(i)));
for (var pair2 : new HashSet<>(input)) {
// TODO Maybe this would be unnecessary if we were to add the = constraints later on
if (pair2 instanceof PairTPHequalRefTypeOrWildcardType && pair2.getLeft().equals(cur)) {
input.remove(pair2);
input.add(new PairTPHequalRefTypeOrWildcardType(start, pair2.getRight()));
}
}
prev = chain.get(i);
} }
} }
} }
@@ -739,6 +816,15 @@ public class ASTToTargetAST {
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());
var variance = cycle.get(0).getVariance();
for (var tph : cycle) {
if (tph.getVariance() != variance) {
variance = 0;
break;
}
}
newTph.setVariance(variance);
referenced.add(newTph); referenced.add(newTph);
addToPairs(input, new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT)); addToPairs(input, new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT));
cycle.add(cycle.get(0)); // Make it a complete cycle cycle.add(cycle.get(0)); // Make it a complete cycle
@@ -752,7 +838,7 @@ public class ASTToTargetAST {
} }
} }
void eliminateInfima(Set<ResultPair<?, ?>> input, Map<TypePlaceholder, TypePlaceholder> equality, Set<TypePlaceholder> referenced) { void eliminateInfima(Set<ResultPair<?, ?>> input, Map<TypePlaceholder, TypePlaceholder> equality) {
var foundInfima = false; var foundInfima = false;
do { do {
foundInfima = false; foundInfima = false;
@@ -767,7 +853,16 @@ public class ASTToTargetAST {
if (infima.size() > 1) { if (infima.size() > 1) {
foundInfima = true; foundInfima = true;
var newTph = TypePlaceholder.fresh(new NullToken()); var newTph = TypePlaceholder.fresh(new NullToken());
referenced.add(newTph); var variance = infima.stream().findFirst().get().right.getVariance();
for (var pair : infima) {
if (pair.right.getVariance() != variance) {
variance = 0;
break;
}
}
newTph.setVariance(variance);
//referenced.add(newTph);
addToPairs(input, new PairTPHsmallerTPH(left, newTph)); addToPairs(input, new PairTPHsmallerTPH(left, newTph));
input.removeAll(infima); input.removeAll(infima);
for (var infimum : infima) { for (var infimum : infima) {

@@ -22,11 +22,15 @@ public record TargetMethod(int access, String name, TargetBlock block, Signature
} }
public static String getSignature(Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType) { public static String getSignature(Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType) {
String ret = "<"; String ret = "";
for (var generic : generics) { if (generics.size() > 0) {
ret += generic.name() + ":" + generic.bound().toDescriptor(); ret += "<";
for (var generic : generics) {
ret += generic.name() + ":" + generic.bound().toDescriptor();
}
ret += ">";
} }
ret += ">("; ret += "(";
for (var param : parameters) { for (var param : parameters) {
ret += param.type().toDescriptor(); ret += param.type().toDescriptor();
} }

@@ -1,5 +1,6 @@
package de.dhbwstuttgart.util; package de.dhbwstuttgart.util;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
public class Pair<T, T1> { public class Pair<T, T1> {
@@ -22,4 +23,17 @@ public class Pair<T, T1> {
public String toString() { public String toString() {
return "(" + key.toString() + "," + value.toString() + ")\n"; return "(" + key.toString() + "," + value.toString() + ")\n";
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair<?, ?> pair = (Pair<?, ?>) o;
return Objects.equals(key, pair.key) && Objects.equals(value, pair.value);
}
@Override
public int hashCode() {
return Objects.hash(key, value);
}
} }

@@ -0,0 +1,105 @@
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.GenericContext;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.GenericDeclarationList;
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
public class GenericsParserTest {
@Test
public void testMethodNoGenerics() {
var signature = "()V";
var generics = ASTFactory.createGenerics(signature);
assertEquals(generics, new GenericDeclarationList(List.of(), new NullToken()));
}
@Test
public void testMethodSimpleGenerics() {
var signature = "<T:Ljava/lang/Object;>()V";
var generics = ASTFactory.createGenerics(signature);
assertEquals(generics, new GenericDeclarationList(
List.of(new GenericTypeVar("T", List.of(ASTToTargetAST.OBJECT), new NullToken(), new NullToken())), new NullToken())
);
}
@Test
public void testMethodExtends() {
var signature = "<T:Ljava/lang/Class<TT;>;>()V";
var generics = ASTFactory.createGenerics(signature);
assertEquals(generics, new GenericDeclarationList(
List.of(new GenericTypeVar("T", List.of(
new RefType(new JavaClassName("java.lang.Class"), List.of(new GenericRefType("T", new NullToken())), new NullToken())),
new NullToken(), new NullToken())), new NullToken()
)
);
}
@Test
public void testMethodVariance() {
var signature = "<T:Ljava/lang/Class<+TT;>;>()V";
var generics = ASTFactory.createGenerics(signature);
assertEquals(generics, new GenericDeclarationList(
List.of(new GenericTypeVar("T", List.of(
new RefType(new JavaClassName("java.lang.Class"), List.of(
new ExtendsWildcardType(new GenericRefType("T", new NullToken()), new NullToken())
), new NullToken())),
new NullToken(), new NullToken())),
new NullToken())
);
}
@Test
public void testMethodTypeVars() {
var signature = "<A:TB;B:LClassA;C:LClassB<TA;>;D:TB;>()V";
var generics = ASTFactory.createGenerics(signature);
assertEquals(generics, new GenericDeclarationList(
List.of(
new GenericTypeVar("A", List.of(new GenericRefType("B", new NullToken())), new NullToken(), new NullToken()),
new GenericTypeVar("B", List.of(new RefType(new JavaClassName("ClassA"), new NullToken())), new NullToken(), new NullToken()),
new GenericTypeVar("C", List.of(new RefType(new JavaClassName("ClassB"),
List.of(new GenericRefType("A", new NullToken())),
new NullToken())), new NullToken(), new NullToken()
),
new GenericTypeVar("D", List.of(new GenericRefType("B", new NullToken())), new NullToken(), new NullToken())
),
new NullToken()
));
}
@Test
public void testMethodComplex() {
var signature = "<T:LClassA<+TT;LClassB<+LClassA;-LClassC<LClassA;>;>;>;U:LClassC<LClassC;>;>()V";
var generics = ASTFactory.createGenerics(signature);
assertEquals(generics, new GenericDeclarationList(
List.of(new GenericTypeVar("T", List.of(
new RefType(new JavaClassName("ClassA"), List.of(
new ExtendsWildcardType(new GenericRefType("T", new NullToken()), new NullToken()),
new RefType(new JavaClassName("ClassB"), List.of(
new ExtendsWildcardType(new RefType(new JavaClassName("ClassA"), new NullToken()), new NullToken()),
new SuperWildcardType(
new RefType(new JavaClassName("ClassC"), List.of(
new RefType(new JavaClassName("ClassA"), new NullToken())
), new NullToken()), new NullToken())
), new NullToken())
), new NullToken())
), new NullToken(), new NullToken()),
new GenericTypeVar("U", List.of(
new RefType(new JavaClassName("ClassC"), List.of(
new RefType(new JavaClassName("ClassC"), new NullToken())
), new NullToken())
), new NullToken(), new NullToken())),
new NullToken()
));
}
}

@@ -575,6 +575,11 @@ public class TestComplete {
assertEquals(fstArgm2, m2.getGenericReturnType()); assertEquals(fstArgm2, m2.getGenericReturnType());
} }
@Test
public void testTXGenerics() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "TXGenerics.jav");
var instance = classFiles.get("TXGenerics").getDeclaredConstructor().newInstance();
}
@Test @Test
public void typedIdTest() throws Exception { public void typedIdTest() throws Exception {

@@ -90,16 +90,15 @@ public class TestGenerics {
var generics = result.genericsResults.get(0); var generics = result.genericsResults.get(0);
assertEquals(0, generics.get(result.clazz).size()); assertEquals(0, generics.get(result.clazz).size());
assertEquals(2, generics.get(m).size()); assertEquals(1, generics.get(m).size());
assertEquals(2, generics.get(main).size()); assertEquals(2, generics.get(main).size());
var N = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m); var N = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m);
var NChain = new BoundsList(new Bound(true, ASTToTargetAST.OBJECT)); var N2 = generics.getBounds(m.getReturnType(), result.clazz, m);
assertEquals(N, NChain);
var Q = generics.getBounds(m.getReturnType(), result.clazz, m); var NChain = new BoundsList(new Bound(true, ASTToTargetAST.OBJECT));
var QChain = new BoundsList(new Bound(true, TypePlaceholder.of("N")), new Bound(true, ASTToTargetAST.OBJECT)); assertEquals(N, N2);
assertEquals(Q, QChain); assertEquals(N2, NChain);
var R = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main); var R = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
assertEquals(R, NChain); assertEquals(R, NChain);
@@ -304,17 +303,18 @@ public class TestGenerics {
var main = result.findMethod("main"); var main = result.findMethod("main");
var generics = result.genericsResults.get(0); var generics = result.genericsResults.get(0);
var Q = generics.getBounds(id.getReturnType(), result.clazz, id); var O = generics.getBounds(id.getReturnType(), result.clazz, id);
var N = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id); var O2 = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id);
assertEquals(Q, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT))); assertEquals(O, O2);
assertEquals(N, new BoundsList(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT))); assertEquals(O2, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT)));
var Q2 = generics.getBounds(main.getReturnType(), result.clazz, main); // TODO Maybe test in other ways if the parameter generics equals the return generics
var R = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main); var S = generics.getBounds(main.getReturnType(), result.clazz, main);
var S = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main); var S2 = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
assertEquals(Q2, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT))); var T = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main);
assertEquals(R, new BoundsList(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT))); assertEquals(S, S2);
assertEquals(S, new BoundsList(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT))); assertEquals(S2, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT)));
assertEquals(T, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT)));
} }
@Test @Test