Compare commits
8 Commits
unif23NoOp
...
parseSigna
Author | SHA1 | Date | |
---|---|---|---|
904bdca2f4 | |||
af4db1817a | |||
d945947362 | |||
a0c25a517d | |||
c35577f948 | |||
fc7844c6a4 | |||
4078239815 | |||
39bde24df7 |
resources
src
main
java
de
dhbwstuttgart
test
11
resources/bytecode/javFiles/TXGenerics.jav
Normal file
11
resources/bytecode/javFiles/TXGenerics.jav
Normal file
@ -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;
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
main(x) {
|
||||
return m(x);
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
public class TestTwoCalls {
|
||||
|
||||
// <O> O -> O
|
||||
id(b) {
|
||||
var c = b;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
// <T, S> (S, T) -> T
|
||||
main(x,y) {
|
||||
id(x);
|
||||
return id(y);
|
||||
|
@ -1000,7 +1000,7 @@ public class Codegen {
|
||||
private void generateConstructor(TargetConstructor constructor) {
|
||||
MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "<init>", constructor.getDescriptor(), constructor.getSignature(), null);
|
||||
if (constructor.txGenerics() != null)
|
||||
mv.visitAttribute(new JavaTXSignatureAttribute(cw.newConst(constructor.getTXSignature())));
|
||||
mv.visitAttribute(new JavaTXSignatureAttribute(constructor.getTXSignature()));
|
||||
|
||||
mv.visitCode();
|
||||
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
|
||||
MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null);
|
||||
if (method.txSignature() != null) {
|
||||
mv.visitAttribute(new JavaTXSignatureAttribute(cw.newConst(method.getTXSignature())));
|
||||
mv.visitAttribute(new JavaTXSignatureAttribute(method.getTXSignature()));
|
||||
}
|
||||
|
||||
System.out.println(method.getDescriptor());
|
||||
@ -1044,11 +1044,14 @@ public class Codegen {
|
||||
}
|
||||
|
||||
private static String generateSignature(TargetClass clazz, Set<TargetGeneric> generics) {
|
||||
String ret = "<";
|
||||
for (var generic : generics) {
|
||||
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
||||
String ret = "";
|
||||
if (generics.size() > 0) {
|
||||
ret += "<";
|
||||
for (var generic : generics) {
|
||||
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
||||
}
|
||||
ret += ">";
|
||||
}
|
||||
ret += ">";
|
||||
ret += clazz.superType().toDescriptor();
|
||||
|
||||
return ret;
|
||||
@ -1060,7 +1063,7 @@ public class Codegen {
|
||||
clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)
|
||||
);
|
||||
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.constructors().forEach(this::generateConstructor);
|
||||
|
@ -3,10 +3,13 @@ package de.dhbwstuttgart.bytecode;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
public class JavaTXSignatureAttribute extends Attribute {
|
||||
final int signature;
|
||||
public String signature;
|
||||
|
||||
protected JavaTXSignatureAttribute(int signature) {
|
||||
public JavaTXSignatureAttribute() {
|
||||
super("JavaTXSignature");
|
||||
}
|
||||
protected JavaTXSignatureAttribute(String signature) {
|
||||
this();
|
||||
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) {
|
||||
var data = new byte[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
|
||||
protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) {
|
||||
var data = new ByteVector();
|
||||
data.putShort(this.signature);
|
||||
data.putShort(classWriter.newConst(this.signature));
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -49,4 +49,17 @@ public class GenericDeclarationList extends SyntaxTreeNode implements Iterable<G
|
||||
public String 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.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Entspricht einem GenericTypeVar, jedoch mit Bounds
|
||||
@ -45,7 +46,7 @@ public class GenericTypeVar extends SyntaxTreeNode
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "BoGTV " + this.name;
|
||||
return "BoGTV " + this.name + " " + this.bounds;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
@ -61,4 +62,17 @@ public class GenericTypeVar extends SyntaxTreeNode
|
||||
public void accept(ASTVisitor visitor) {
|
||||
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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||
import de.dhbwstuttgart.bytecode.JavaTXSignatureAttribute;
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.GenericContext;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
|
||||
import de.dhbwstuttgart.syntaxtree.Field;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||
@ -22,7 +19,14 @@ import de.dhbwstuttgart.syntaxtree.*;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.Block;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.Statement;
|
||||
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.apache.commons.io.IOUtils;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
|
||||
/**
|
||||
* Anmerkung:
|
||||
@ -32,21 +36,76 @@ import org.antlr.v4.runtime.Token;
|
||||
public class ASTFactory {
|
||||
|
||||
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());
|
||||
List<Method> methoden = new ArrayList<>();
|
||||
List<de.dhbwstuttgart.syntaxtree.Constructor> konstruktoren = new ArrayList<>();
|
||||
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> allDeclaredMethods = new HashSet<>(Arrays.asList(jreClass.getDeclaredMethods()));
|
||||
Set<java.lang.reflect.Method> allInheritedMethods = new HashSet<>(allMethods);
|
||||
allInheritedMethods.removeAll(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){
|
||||
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<>();
|
||||
for(java.lang.reflect.Field field : jreClass.getDeclaredFields()){
|
||||
@ -72,7 +131,8 @@ public class ASTFactory {
|
||||
for(Type jreInterface : jreClass.getGenericInterfaces()){
|
||||
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
|
||||
|
||||
@ -87,7 +147,7 @@ public class ASTFactory {
|
||||
// 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();
|
||||
RefTypeOrTPHOrWildcardOrGeneric returnType = createType(inClass);
|
||||
Parameter[] jreParams = constructor.getParameters();
|
||||
@ -101,7 +161,7 @@ public class ASTFactory {
|
||||
}
|
||||
ParameterList parameterList = new ParameterList(params, 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();
|
||||
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 */));
|
||||
}
|
||||
|
||||
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();
|
||||
RefTypeOrTPHOrWildcardOrGeneric returnType;
|
||||
Type jreRetType;
|
||||
@ -133,19 +193,142 @@ public class ASTFactory {
|
||||
}
|
||||
ParameterList parameterList = new ParameterList(params, 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();
|
||||
|
||||
return new Method(jreMethod.getModifiers(), name,returnType, parameterList, block, gtvDeclarations, offset, isInherited);
|
||||
}
|
||||
|
||||
public static GenericDeclarationList createGenerics(TypeVariable[] typeParameters, Class context, String methodName){
|
||||
List<de.dhbwstuttgart.syntaxtree.GenericTypeVar> gtvs = new ArrayList<>();
|
||||
for(TypeVariable jreTV : typeParameters){
|
||||
de.dhbwstuttgart.syntaxtree.GenericTypeVar gtv = createGeneric(jreTV, jreTV.getName(), context, methodName);
|
||||
gtvs.add(gtv);
|
||||
public static GenericDeclarationList createGenerics(TypeVariable[] typeParameters, Class context, String methodName, String signature) {
|
||||
if (signature == null) {
|
||||
List<de.dhbwstuttgart.syntaxtree.GenericTypeVar> gtvs = new ArrayList<>();
|
||||
for(TypeVariable jreTV : typeParameters){
|
||||
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){
|
||||
|
@ -5,6 +5,8 @@ import de.dhbwstuttgart.syntaxtree.ASTVisitor;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSetVisitor;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Stellt eine Wildcard mit oberer Grenze dar.
|
||||
* z.B. void test(? extends Number var){..}
|
||||
@ -54,9 +56,16 @@ public class ExtendsWildcardType extends WildcardType{
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(this.innerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
if (this == o) return true;
|
||||
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 org.antlr.v4.runtime.Token;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class GenericRefType extends RefTypeOrTPHOrWildcardOrGeneric
|
||||
{
|
||||
private String name;
|
||||
@ -33,14 +35,20 @@ public class GenericRefType extends RefTypeOrTPHOrWildcardOrGeneric
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
GenericRefType that = (GenericRefType) o;
|
||||
return name.equals(that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "GTV " + this.name;
|
||||
|
@ -2,9 +2,12 @@ package de.dhbwstuttgart.syntaxtree.type;
|
||||
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.ASTVisitor;
|
||||
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSetVisitor;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Stellt eine Wildcard mit unterer Grenze dar.
|
||||
* z.B. void test(? super Integer var){..}
|
||||
@ -65,9 +68,16 @@ public class SuperWildcardType extends WildcardType{
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(this.innerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
if (this == o) return true;
|
||||
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.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.result.*;
|
||||
import org.objectweb.asm.Attribute;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -170,7 +172,6 @@ public class ASTToTargetAST {
|
||||
for (var pair : simplifiedConstraints) {
|
||||
if (pair.left.equals(typeVariable) && typeVariables.contains(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;
|
||||
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
|
||||
|
||||
superType = methodCall.receiverType;
|
||||
@ -211,7 +212,7 @@ public class ASTToTargetAST {
|
||||
var optMethod = findMethod(owner, methodCall.name, methodCall.getArgumentList());
|
||||
if (optMethod.isEmpty()) return;
|
||||
var method = optMethod.get();
|
||||
var generics = generics(owner, method).javaGenerics();
|
||||
var generics = generics(owner, method).txGenerics();
|
||||
|
||||
// transitive and
|
||||
var all = transitiveClosure(generics);
|
||||
@ -226,24 +227,24 @@ public class ASTToTargetAST {
|
||||
|
||||
// Loop from hell
|
||||
outer:
|
||||
for (var tph : typeVariables) {
|
||||
if (typeVariablesOfClass.contains(tph)) continue;
|
||||
for (var R1 : typeVariables) {
|
||||
if (typeVariablesOfClass.contains(R1)) continue;
|
||||
for (var generic : all) {
|
||||
if (!(generic.getRight() instanceof TypePlaceholder type))
|
||||
continue;
|
||||
|
||||
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;
|
||||
|
||||
for (var tph2 : typeVariables) {
|
||||
for (var R2 : typeVariables) {
|
||||
for (var pair2 : simplifiedConstraints) {
|
||||
if (!(pair2.right.equals(tph2) && pair2.left.equals(type)))
|
||||
if (!(pair2.right.equals(R2) && pair2.left.equals(type)))
|
||||
continue;
|
||||
if (tph.equals(tph2)) continue;
|
||||
if (!T1s.contains(tph) || !tph2.equals(T2)) continue;
|
||||
if (R1.equals(R2)) continue;
|
||||
if (!T1s.contains(R1) || !R2.equals(T2)) continue;
|
||||
|
||||
var newPair = new PairTPHsmallerTPH(tph, tph2);
|
||||
var newPair = new PairTPHsmallerTPH(R1, R2);
|
||||
newPairs.add(newPair);
|
||||
|
||||
if (!containsRelation(result, newPair))
|
||||
@ -268,7 +269,7 @@ public class ASTToTargetAST {
|
||||
|
||||
@Override
|
||||
public void visit(Assign assign) {
|
||||
superType = assign.lefSide.getType();
|
||||
superType = assign.rightSide.getType();
|
||||
assign.rightSide.accept(this);
|
||||
}
|
||||
|
||||
@ -521,9 +522,6 @@ public class ASTToTargetAST {
|
||||
super.visit(methodCall);
|
||||
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);
|
||||
|
||||
{ // Java Generics
|
||||
eliminateTransitives(javaResult);
|
||||
var referenced = new HashSet<TypePlaceholder>();
|
||||
|
||||
eliminateCycles(javaResult, equality, referenced);
|
||||
eliminateInfima(javaResult, equality, referenced);
|
||||
eliminateInfima(javaResult, equality);
|
||||
|
||||
var usedTphs = new HashSet<TypePlaceholder>();
|
||||
// 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);
|
||||
equalizeTypeVariables(javaResult, equality);
|
||||
usedTPHsOfMethods.put(method, usedTphs);
|
||||
addMissingObjectBounds(javaResult, genericsOfClass);
|
||||
}
|
||||
{
|
||||
var referenced = new HashSet<TypePlaceholder>();
|
||||
// JavaTX Generics
|
||||
eliminateInfima(txResult, txEquality, referenced);
|
||||
eliminateTransitives(txResult);
|
||||
eliminateInfima(txResult, txEquality);
|
||||
|
||||
for (var param : method.getParameterList().getFormalparalist()) {
|
||||
referenced.addAll(findTypeVariables(param.getType(), txEquality));
|
||||
@ -584,12 +585,36 @@ public class ASTToTargetAST {
|
||||
referenced.addAll(txTypeVariablesOfClass);
|
||||
|
||||
eliminateInnerTypeVariables(referenced, txResult);
|
||||
addMissingObjectBounds(txResult, txGenericsOfClass);
|
||||
}
|
||||
|
||||
System.out.println(method.name + ": " + txResult + " & " + javaResult);
|
||||
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) {
|
||||
if (type instanceof TypePlaceholder tph) {
|
||||
tph = equality.getOrDefault(tph, tph);
|
||||
@ -634,34 +659,86 @@ public class ASTToTargetAST {
|
||||
findAllBounds(field.getType(), txResult, txEquality);
|
||||
}
|
||||
|
||||
eliminateTransitives(javaResult);
|
||||
eliminateTransitives(txResult);
|
||||
System.out.println(javaResult);
|
||||
var referenced = new HashSet<TypePlaceholder>();
|
||||
eliminateCycles(javaResult, equality, referenced);
|
||||
eliminateInfima(javaResult, equality, referenced);
|
||||
eliminateInfima(javaResult, equality);
|
||||
var txReferenced = new HashSet<TypePlaceholder>();
|
||||
eliminateInfima(txResult, txEquality, txReferenced);
|
||||
eliminateInfima(txResult, txEquality);
|
||||
|
||||
eliminateInnerTypeVariablesOfClass(classOrInterface, javaResult, equality, referenced);
|
||||
equalizeTypeVariables(javaResult, equality);
|
||||
eliminateInnerTypeVariablesOfClass(classOrInterface, txResult, txEquality, txReferenced);
|
||||
|
||||
addMissingObjectBounds(javaResult, null);
|
||||
addMissingObjectBounds(txResult, null);
|
||||
|
||||
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + txResult + ", " + javaResult);
|
||||
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) {
|
||||
System.out.println(input);
|
||||
for (var pair : new HashSet<>(input)) {
|
||||
if (pair instanceof PairTPHsmallerTPH ptph) {
|
||||
System.out.println(pair + " " + ptph.left.getVariance() + " " + ptph.right.getVariance());
|
||||
if (ptph.left.getVariance() == 1 && ptph.right.getVariance() == -1) {
|
||||
addToEquality(equality, ptph.left, ptph.right);
|
||||
input.remove(ptph);
|
||||
for (var pair2 : new HashSet<>(simplifiedConstraints)) {
|
||||
if (pair2.right.equals(ptph.left)) {
|
||||
simplifiedConstraints.remove(pair2);
|
||||
simplifiedConstraints.add(new PairTPHsmallerTPH(pair2.left, ptph.right));
|
||||
var chain = new ArrayList<TypePlaceholder>();
|
||||
chain.add(ptph.left);
|
||||
chain.add(ptph.right);
|
||||
|
||||
outer: while (true) {
|
||||
var added = false;
|
||||
for (var pair2 : input) {
|
||||
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);
|
||||
for (var cycle : cycles) {
|
||||
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);
|
||||
addToPairs(input, new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT));
|
||||
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;
|
||||
do {
|
||||
foundInfima = false;
|
||||
@ -767,7 +853,16 @@ public class ASTToTargetAST {
|
||||
if (infima.size() > 1) {
|
||||
foundInfima = true;
|
||||
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));
|
||||
input.removeAll(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) {
|
||||
String ret = "<";
|
||||
for (var generic : generics) {
|
||||
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
||||
String ret = "";
|
||||
if (generics.size() > 0) {
|
||||
ret += "<";
|
||||
for (var generic : generics) {
|
||||
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
||||
}
|
||||
ret += ">";
|
||||
}
|
||||
ret += ">(";
|
||||
ret += "(";
|
||||
for (var param : parameters) {
|
||||
ret += param.type().toDescriptor();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.dhbwstuttgart.util;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Pair<T, T1> {
|
||||
@ -22,4 +23,17 @@ public class Pair<T, T1> {
|
||||
public String toString() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
105
src/test/java/GenericsParserTest.java
Normal file
105
src/test/java/GenericsParserTest.java
Normal file
@ -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());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTXGenerics() throws Exception {
|
||||
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "TXGenerics.jav");
|
||||
var instance = classFiles.get("TXGenerics").getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typedIdTest() throws Exception {
|
||||
|
@ -90,16 +90,15 @@ public class TestGenerics {
|
||||
|
||||
var generics = result.genericsResults.get(0);
|
||||
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());
|
||||
|
||||
var N = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m);
|
||||
var NChain = new BoundsList(new Bound(true, ASTToTargetAST.OBJECT));
|
||||
assertEquals(N, NChain);
|
||||
var N2 = generics.getBounds(m.getReturnType(), result.clazz, m);
|
||||
|
||||
var Q = generics.getBounds(m.getReturnType(), result.clazz, m);
|
||||
var QChain = new BoundsList(new Bound(true, TypePlaceholder.of("N")), new Bound(true, ASTToTargetAST.OBJECT));
|
||||
assertEquals(Q, QChain);
|
||||
var NChain = new BoundsList(new Bound(true, ASTToTargetAST.OBJECT));
|
||||
assertEquals(N, N2);
|
||||
assertEquals(N2, NChain);
|
||||
|
||||
var R = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
|
||||
assertEquals(R, NChain);
|
||||
@ -304,17 +303,18 @@ public class TestGenerics {
|
||||
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);
|
||||
assertEquals(Q, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT)));
|
||||
assertEquals(N, new BoundsList(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT)));
|
||||
var O = generics.getBounds(id.getReturnType(), result.clazz, id);
|
||||
var O2 = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id);
|
||||
assertEquals(O, O2);
|
||||
assertEquals(O2, new BoundsList(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);
|
||||
assertEquals(Q2, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT)));
|
||||
assertEquals(R, new BoundsList(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT)));
|
||||
assertEquals(S, new BoundsList(new Bound(true, TypePlaceholder.of("Q")), new Bound(true, ASTToTargetAST.OBJECT)));
|
||||
// TODO Maybe test in other ways if the parameter generics equals the return generics
|
||||
var S = generics.getBounds(main.getReturnType(), result.clazz, main);
|
||||
var S2 = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
|
||||
var T = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main);
|
||||
assertEquals(S, S2);
|
||||
assertEquals(S2, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT)));
|
||||
assertEquals(T, new BoundsList(new Bound(true, ASTToTargetAST.OBJECT)));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Reference in New Issue
Block a user