Add missing functions and test the signature parser

This commit is contained in:
Victorious3 2023-04-19 14:56:59 +02:00
parent fc7844c6a4
commit c35577f948
7 changed files with 256 additions and 61 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -18,8 +18,11 @@ import de.dhbwstuttgart.syntaxtree.type.Void;
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.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;
@ -40,7 +43,10 @@ public class ASTFactory {
// Load class with asm to figure out if there's a JavaTX signature
try {
var bytes = Files.readAllBytes(Path.of(jreClass.getProtectionDomain().getCodeSource().getLocation().getPath()));
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) {
@ -77,6 +83,8 @@ public class ASTFactory {
classReader.accept(classVisitor, new Attribute[]{new JavaTXSignatureAttribute()}, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
classSignature = classVisitor.classSignature;
}
} catch (IOException e) {
// Skip
}
@ -125,7 +133,7 @@ public class ASTFactory {
implementedInterfaces.add((RefType) createType(jreInterface));
}
GenericDeclarationList genericDeclarationList = createGenerics(classSignature, jreClass, null);
GenericDeclarationList genericDeclarationList = createGenerics(classSignature);
Token offset = new NullToken(); //Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde
@ -154,7 +162,7 @@ public class ASTFactory {
}
ParameterList parameterList = new ParameterList(params, new NullToken());
Block block = new Block(new ArrayList<Statement>(), new NullToken());
GenericDeclarationList gtvDeclarations = createGenerics(signature, inClass, constructor.getName());
GenericDeclarationList gtvDeclarations = createGenerics(signature);
Token offset = new NullToken();
int modifier = constructor.getModifiers();
@ -186,17 +194,22 @@ public class ASTFactory {
}
ParameterList parameterList = new ParameterList(params, new NullToken());
Block block = new Block(new ArrayList<Statement>(), new NullToken());
GenericDeclarationList gtvDeclarations = createGenerics(signature, inClass, jreMethod.getName());
GenericDeclarationList gtvDeclarations = createGenerics(signature);
Token offset = new NullToken();
return new Method(jreMethod.getModifiers(), name,returnType, parameterList, block, gtvDeclarations, offset, isInherited);
}
public static GenericDeclarationList createGenerics(String signature, Class context, String methodName){
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<>();
Stack<RefTypeOrTPHOrWildcardOrGeneric> bound = new Stack<>();
final Stack<RefTypeOrTPHOrWildcardOrGeneric> bound = new Stack<>();
final Stack<RefType> classTypes = new Stack<>();
char wildcard = '=';
@Override
public void visitFormalTypeParameter(String name) {
@ -206,26 +219,68 @@ public class ASTFactory {
@Override
public void visitTypeVariable(String name) {
((RefType) bound.peek()).getParaList().add(new GenericRefType(name, new NullToken()));
var refType = new GenericRefType(name, new NullToken());
pushType(refType);
}
@Override
public void visitClassType(String name) {
var currentBound = new RefType(new JavaClassName(name), new ArrayList<>(), new NullToken());
bound.push(currentBound);
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() {
var last = bound.pop();
if (bound.empty()) bounds.add(last);
else {
((RefType) bound.peek()).getParaList().add(last);
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());
}
}
}
};
@ -233,7 +288,7 @@ public class ASTFactory {
var sr = new SignatureReader(signature);
sr.accept(signatureVisitor);
return new GenericDeclarationList(gtvs,new NullToken());
return new GenericDeclarationList(gtvs, new NullToken());
}
private static RefTypeOrTPHOrWildcardOrGeneric createType(java.lang.reflect.Type type){

View File

@ -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);
}
}

View File

@ -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;
@ -35,10 +37,16 @@ public class GenericRefType extends RefTypeOrTPHOrWildcardOrGeneric
@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;
GenericRefType that = (GenericRefType) o;
return name.equals(that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public String toString()

View File

@ -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);
}
}

View File

@ -0,0 +1,86 @@
import de.dhbwstuttgart.parser.NullToken;
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 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()
));
}
}