Add missing functions and test the signature parser
This commit is contained in:
parent
fc7844c6a4
commit
c35577f948
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,11 @@ import de.dhbwstuttgart.syntaxtree.type.Void;
|
|||||||
import de.dhbwstuttgart.syntaxtree.*;
|
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.util.Pair;
|
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.*;
|
||||||
import org.objectweb.asm.signature.SignatureReader;
|
import org.objectweb.asm.signature.SignatureReader;
|
||||||
import org.objectweb.asm.signature.SignatureVisitor;
|
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
|
// Load class with asm to figure out if there's a JavaTX signature
|
||||||
try {
|
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 classReader = new ClassReader(bytes);
|
||||||
|
|
||||||
var classVisitor = new ClassVisitor(Opcodes.ASM7) {
|
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);
|
classReader.accept(classVisitor, new Attribute[]{new JavaTXSignatureAttribute()}, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||||
classSignature = classVisitor.classSignature;
|
classSignature = classVisitor.classSignature;
|
||||||
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Skip
|
// Skip
|
||||||
}
|
}
|
||||||
@ -125,7 +133,7 @@ public class ASTFactory {
|
|||||||
implementedInterfaces.add((RefType) createType(jreInterface));
|
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
|
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());
|
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(signature, inClass, constructor.getName());
|
GenericDeclarationList gtvDeclarations = createGenerics(signature);
|
||||||
Token offset = new NullToken();
|
Token offset = new NullToken();
|
||||||
int modifier = constructor.getModifiers();
|
int modifier = constructor.getModifiers();
|
||||||
|
|
||||||
@ -186,17 +194,22 @@ 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(signature, inClass, jreMethod.getName());
|
GenericDeclarationList gtvDeclarations = createGenerics(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(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 gtvs = new ArrayList<GenericTypeVar>();
|
||||||
var signatureVisitor = new SignatureVisitor(Opcodes.ASM7) {
|
var signatureVisitor = new SignatureVisitor(Opcodes.ASM7) {
|
||||||
List<RefTypeOrTPHOrWildcardOrGeneric> bounds = new ArrayList<>();
|
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
|
@Override
|
||||||
public void visitFormalTypeParameter(String name) {
|
public void visitFormalTypeParameter(String name) {
|
||||||
@ -206,26 +219,68 @@ public class ASTFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitTypeVariable(String name) {
|
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
|
@Override
|
||||||
public void visitClassType(String name) {
|
public void visitClassType(String name) {
|
||||||
var currentBound = new RefType(new JavaClassName(name), new ArrayList<>(), new NullToken());
|
var refType = new RefType(new JavaClassName(name.replaceAll("/", ".")), new ArrayList<>(), new NullToken());
|
||||||
bound.push(currentBound);
|
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
|
@Override
|
||||||
public SignatureVisitor visitTypeArgument(char wildcard) {
|
public SignatureVisitor visitTypeArgument(char wildcard) {
|
||||||
|
this.wildcard = wildcard;
|
||||||
return this;
|
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
|
@Override
|
||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
var last = bound.pop();
|
wildcard = '=';
|
||||||
if (bound.empty()) bounds.add(last);
|
var classType = (RefType) classTypes.pop();
|
||||||
else {
|
if (!classTypes.isEmpty()) {
|
||||||
((RefType) bound.peek()).getParaList().add(last);
|
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);
|
var sr = new SignatureReader(signature);
|
||||||
sr.accept(signatureVisitor);
|
sr.accept(signatureVisitor);
|
||||||
|
|
||||||
return new GenericDeclarationList(gtvs,new NullToken());
|
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;
|
||||||
@ -35,10 +37,16 @@ public class GenericRefType extends RefTypeOrTPHOrWildcardOrGeneric
|
|||||||
|
|
||||||
@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
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
86
src/test/java/GenericsParserTest.java
Normal file
86
src/test/java/GenericsParserTest.java
Normal 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()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user