diff --git a/pom.xml b/pom.xml index ae2a8ac5..6f1d010c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,218 +1,188 @@ - 4.0.0 - de.dhbwstuttgart - JavaTXcompiler - 0.1.0 - JavaTXcompiler - http://maven.apache.org - jar + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/maven-v4_0_0.xsd"> + 4.0.0 + de.dhbwstuttgart + JavaTXcompiler + jar + + 0.1 + JavaTXcompiler + http://maven.apache.org + + + junit + junit + 4.0 + test + + + org.antlr + antlr4 + 4.7 + + + commons-io + commons-io + 2.6 + + +com.google.guava + guava + 22.0 + + + org.reflections + reflections + 0.9.11 + + + + org.ow2.asm + asm + 7.0 + + + + - - 1.8 - 1.8 - UTF-8 - 1.2.0 - - - - maven-repository - MyCo Internal Repository - file:///${project.basedir}/maven-repository/ - - + + target + target/classes + ${project.artifactId}-${project.version} + target/test-classes + src/ + test/ + + + org.antlr + antlr4-maven-plugin + 4.7 + + + antlr + + antlr4 + + + src/de/dhbwstuttgart/parser/antlr/ + src/de/dhbwstuttgart/parser/antlr/ + -package de.dhbwstuttgart.parser.antlr + + + + aspParser + + antlr4 + + + src/de/dhbwstuttgart/sat/asp/parser/antlr/ + src/de/dhbwstuttgart/sat/asp/parser/antlr/ + + -package + de.dhbwstuttgart.sat.asp.parser.antlr + + + - - - - org.antlr - antlr4 - 4.7 - - - commons-io - commons-io - 2.6 - - - com.google.guava - guava - 27.0.1-jre - - - org.reflections - reflections - 0.9.11 - - - org.ow2.asm - asm - [6.1.1,) - - - junit - junit - 4.12 - test - - - - - target - target/classes - ${project.artifactId}-${project.version} - target/test-classes - - - org.antlr - antlr4-maven-plugin - 4.7 - - - antlr - - antlr4 - - - src/main/antlr4/java8 - ${project.basedir}/target/generated-sources/antlr4/de/dhbwstuttgart/parser/antlr - - -package - de.dhbwstuttgart.parser.antlr - - - - - aspParser - - antlr4 - - - src/main/antlr4/sat/ - ${project.basedir}/target/generated-sources/antlr4/de/dhbwstuttgart/sat/asp/parser/antlr - - -package - de.dhbwstuttgart.sat.asp.parser.antlr - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.0.0-M1 - - true - - - - maven-assembly-plugin - - - package - - single - - - - - - jar-with-dependencies - - - - - org.apache.maven.plugins - maven-site-plugin - 3.7.1 - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 3.0.0 - - - org.reficio - p2-maven-plugin - 1.3.0 - - - default-cli - - - - - - de.dhbwstuttgart:JavaTXcompiler:0.1 - - - org.reflections:reflections:0.9.11 - - - com.google.guava:guava:27.0.1-jre - - - javax.annotation:javax.annotation-api:1.3.1 - - - org.glassfish:javax.annotation:3.1.1 - - - - - - - - org.eclipse.jetty - jetty-maven-plugin - 9.4.14.v20181114 - - 10 - ${basedir}/target/repository/ - - /site - - - jar - - - - - org.eclipse.tycho - tycho-p2-repository-plugin - ${tycho.version} - - - p2:site - - archive-repository - - - - - - - - - - reficio - http://repo.reficio.org/maven/ - - - repo2_maven_org - http://repo2.maven.org/maven2 - - - - - maven-repository - file:///${project.basedir}/target - - + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + + + + org.reficio + p2-maven-plugin + 1.1.2-SNAPSHOT + + + default-cli + + + + + + de.dhbwstuttgart:JavaTXcompiler:0.1 + + org.reflections:reflections:0.9.11 + com.google.guava:guava:22.0 + javax.annotation:javax.annotation-api:1.3.1 + org.glassfish:javax.annotation:3.1.1 + + + + + + + org.eclipse.tycho + tycho-p2-repository-plugin + ${tycho.version} + + + package + + archive-repository + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + + + + + + reficio + http://repo.reficio.org/maven/ + + + + + maven-repository + file:///${project.basedir}/target + + + + 1.8 + 1.8 + 0.23.0 + + + + maven-repository + MyCo Internal Repository + file:///${project.basedir}/maven-repository/ + + diff --git a/src/de/dhbwstuttgart/bytecode/TPHExtractor.java b/src/de/dhbwstuttgart/bytecode/TPHExtractor.java new file mode 100644 index 00000000..d9a95311 --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/TPHExtractor.java @@ -0,0 +1,78 @@ +/** + * + */ +package de.dhbwstuttgart.bytecode; + +import java.util.ArrayList; +import java.util.HashMap; + +import de.dhbwstuttgart.bytecode.constraint.ExtendsConstraint; +import de.dhbwstuttgart.bytecode.constraint.TPHConstraint; +import de.dhbwstuttgart.bytecode.constraint.TPHConstraint.Relation; +import de.dhbwstuttgart.bytecode.utilities.MethodAndTPH; +import de.dhbwstuttgart.syntaxtree.AbstractASTWalker; +import de.dhbwstuttgart.syntaxtree.Method; +import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; +import de.dhbwstuttgart.typeinference.result.GenericInsertPair; +import de.dhbwstuttgart.typeinference.result.ResultSet; + +/** + * @author Fayez Abu Alia + * + */ +public class TPHExtractor extends AbstractASTWalker{ + // Alle TPHs der Felder werden iKopf der Klasse definiert + // alle TPHs der Klasse: (TPH, is in Method?) + final HashMap allTPHS = new HashMap<>(); + MethodAndTPH methodAndTph; + Boolean inMethod = false; + public final ArrayList ListOfMethodsAndTph = new ArrayList<>(); + final ArrayList allPairs = new ArrayList<>(); + public final ArrayList allCons = new ArrayList<>(); + private ResultSet resultSet; + + public TPHExtractor() { + + } + + public void setResultSet(ResultSet resultSet) { + this.resultSet = resultSet; + } + + @Override + public void visit(TypePlaceholder tph) { + if(resultSet.resolveType(tph).resolvedType instanceof TypePlaceholder) { + TypePlaceholder resolvedTPH = (TypePlaceholder) resultSet.resolveType(tph).resolvedType; + if(inMethod) + methodAndTph.getTphs().add(resolvedTPH.getName()); + + allTPHS.put(resolvedTPH,inMethod); + resultSet.resolveType(tph).additionalGenerics.forEach(ag ->{ + if(ag.contains(resolvedTPH)&&ag.TA1.equals(resolvedTPH)&&!contains(allPairs,ag)) { + if(inMethod) + methodAndTph.getPairs().add(ag); + allPairs.add(ag); + TPHConstraint con = new ExtendsConstraint(ag.TA1.getName(), ag.TA2.getName(), Relation.EXTENDS); + allCons.add(con); + } + }); + } + } + private boolean contains(ArrayList pairs, GenericInsertPair genPair) { + for(int i=0; i listOfResultSets; @@ -54,6 +56,8 @@ public class BytecodeGen implements ASTVisitor { private SourceFile sf; private String path; + private Optional fieldInitializations; + private int indexOfFirstParam = 0; private String superClass; @@ -118,6 +122,7 @@ public class BytecodeGen implements ASTVisitor { int acc = isInterface?classOrInterface.getModifiers()+Opcodes.ACC_ABSTRACT:classOrInterface.getModifiers()+Opcodes.ACC_SUPER; + fieldInitializations = classOrInterface.getfieldInitializations(); // resultSet = listOfResultSets.get(0); boolean isConsWithNoParamsVisited = false; @@ -125,6 +130,7 @@ public class BytecodeGen implements ASTVisitor { for(ResultSet rs : listOfResultSets) { superClass = classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()); resultSet = rs; + tphExtractor.setResultSet(resultSet); // Nur einmal ausführen!! if(!isVisited) { classOrInterface.accept(tphExtractor); @@ -154,10 +160,12 @@ public class BytecodeGen implements ASTVisitor { } for(Constructor c : classOrInterface.getConstructors()) { - if(!isConsWithNoParamsVisited) +// if(!isConsWithNoParamsVisited) { c.accept(this); - if(!c.getParameterList().iterator().hasNext()) - isConsWithNoParamsVisited = true; +// } + +// if(!c.getParameterList().iterator().hasNext()) +// isConsWithNoParamsVisited = true; } for(Method m : classOrInterface.getMethods()) { @@ -192,7 +200,7 @@ public class BytecodeGen implements ASTVisitor { field.getParameterList().accept(this); String methParamTypes = field.name+"%%"; - + Iterator itr = field.getParameterList().iterator(); while(itr.hasNext()) { FormalParameter fp = itr.next(); @@ -201,6 +209,7 @@ public class BytecodeGen implements ASTVisitor { } if(methodNameAndParamsT.contains(methParamTypes)) { + System.out.println("ignore - Method: "+field.name +" , paramsType: "+methParamTypes); return; } methodNameAndParamsT.add(methParamTypes); @@ -223,13 +232,18 @@ public class BytecodeGen implements ASTVisitor { Signature signature = new Signature(field, genericsAndBounds,methodParamsAndTypes,resultSet,constraints); sig = signature.toString(); } + if(field.getParameterList().iterator().hasNext()) + System.out.println(field.getParameterList().iterator().next().getType().acceptTV(new TypeToDescriptor())); + NormalConstructor constructor = new NormalConstructor(field,genericsAndBounds,hasGen); desc = constructor.accept(new DescriptorToString(resultSet)); + System.out.println("Constructor: " + field.getName() + " Sig: "+ sig + " Desc: " + desc); MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", desc, sig, null); mv.visitCode(); + Block block = fieldInitializations.get().block; BytecodeGenMethod gen = new BytecodeGenMethod(className,superClass,resultSet,field, mv,paramsAndLocals,cw, - genericsAndBoundsMethod,genericsAndBounds,isInterface,classFiles, sf,path); - if(!field.getParameterList().iterator().hasNext()) { + genericsAndBoundsMethod,genericsAndBounds,isInterface,classFiles, sf,path, block); + if(!field.getParameterList().iterator().hasNext() && !(field.block.statements.get(field.block.statements.size()-1) instanceof ReturnVoid)) { mv.visitInsn(Opcodes.RETURN); } mv.visitMaxs(0, 0); @@ -558,52 +572,5 @@ public class BytecodeGen implements ASTVisitor { throw new NotImplementedException(); } - public class TPHExtractor extends AbstractASTWalker{ - // Alle TPHs der Felder werden iKopf der Klasse definiert - // alle TPHs der Klasse: (TPH, is in Method?) - final HashMap allTPHS = new HashMap<>(); - MethodAndTPH methodAndTph; - Boolean inMethod = false; - public final ArrayList ListOfMethodsAndTph = new ArrayList<>(); - final ArrayList allPairs = new ArrayList<>(); - public final ArrayList allCons = new ArrayList<>(); - - @Override - public void visit(TypePlaceholder tph) { - if(resultSet.resolveType(tph).resolvedType instanceof TypePlaceholder) { - TypePlaceholder resolvedTPH = (TypePlaceholder) resultSet.resolveType(tph).resolvedType; - if(inMethod) - methodAndTph.getTphs().add(resolvedTPH); - - allTPHS.put(resolvedTPH,inMethod); - resultSet.resolveType(tph).additionalGenerics.forEach(ag ->{ - if(ag.contains(resolvedTPH)&&ag.TA1.equals(resolvedTPH)&&!contains(allPairs,ag)) { - if(inMethod) - methodAndTph.getPairs().add(ag); - allPairs.add(ag); - TPHConstraint con = new ExtendsConstraint(ag.TA1.getName(), ag.TA2.getName(), Relation.EXTENDS); - allCons.add(con); - } - }); - } - } - private boolean contains(ArrayList pairs, GenericInsertPair genPair) { - for(int i=0; i classFiles; private ArrayList varsFunInterface = new ArrayList<>();; + // generate bytecode for constructor + public BytecodeGenMethod(String className, String superClass,ResultSet resultSet, Method m, MethodVisitor mv, + HashMap paramsAndLocals, ClassWriter cw, HashMap genericsAndBoundsMethod, + HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, + SourceFile sf,String path, Block block) { + this.className = className; + this.superClass = superClass; + this.resultSet = resultSet; + this.m = m; + this.mv = mv; + this.paramsAndLocals = paramsAndLocals; + this.cw = cw; + this.genericsAndBoundsMethod = genericsAndBoundsMethod; + this.genericsAndBounds = genericsAndBounds; + this.isInterface = isInterface; + this.classFiles = classFiles; + this.sf = sf; + this.path = path; + if(block != null) + this.blockFieldInit = block; + this.m.block.accept(this); + + + } + public BytecodeGenMethod(String className, String superClass,ResultSet resultSet, Method m, MethodVisitor mv, HashMap paramsAndLocals, ClassWriter cw, HashMap genericsAndBoundsMethod, HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, SourceFile sf,String path) { @@ -109,8 +136,8 @@ public class BytecodeGenMethod implements StatementVisitor { } - public BytecodeGenMethod(LambdaExpression lambdaExpression, ResultSet resultSet, MethodVisitor mv, - int indexOfFirstParamLam, boolean isInterface, HashMap classFiles, String path, int lamCounter) { + public BytecodeGenMethod(LambdaExpression lambdaExpression, ArrayList usedVars, ResultSet resultSet, MethodVisitor mv, + int indexOfFirstParamLam, boolean isInterface, HashMap classFiles, String path, int lamCounter, SourceFile sf) { this.resultSet = resultSet; this.mv = mv; @@ -118,8 +145,15 @@ public class BytecodeGenMethod implements StatementVisitor { this.classFiles = classFiles; this.path = path; this.lamCounter = lamCounter; + this.sf = sf; Iterator itr = lambdaExpression.params.iterator(); int i = indexOfFirstParamLam; + + for(String var : usedVars) { + this.paramsAndLocals.put(var, i); + i++; + } + while (itr.hasNext()) { FormalParameter fp = itr.next(); this.paramsAndLocals.put(fp.getName(), i); @@ -154,6 +188,17 @@ public class BytecodeGenMethod implements StatementVisitor { superCall.arglist.accept(this); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, this.superClass, superCall.name, "()V", isInterface); + + if(blockFieldInit!=null && !isBlockFieldInitVisited) { + isBlockFieldInitVisited =true; + //blockFieldInit.accept(this); + for(Statement stmt : blockFieldInit.statements) { + if(stmt instanceof SuperCall) + continue; + + stmt.accept(this); + } + } } // ?? @@ -378,6 +423,12 @@ public class BytecodeGenMethod implements StatementVisitor { case BIGGEREQUAL: mv.visitJumpInsn(Opcodes.IF_ICMPLT, branchLabel); break; + case EQUAL: + mv.visitJumpInsn(Opcodes.IF_ICMPNE, branchLabel); + break; + case NOTEQUAL: + mv.visitJumpInsn(Opcodes.IFEQ, branchLabel); + break; default: break; } @@ -403,6 +454,12 @@ public class BytecodeGenMethod implements StatementVisitor { case BIGGEREQUAL: mv.visitJumpInsn(Opcodes.IFLT, branchLabel); break; + case EQUAL: + mv.visitJumpInsn(Opcodes.IFNE, branchLabel); + break; + case NOTEQUAL: + mv.visitJumpInsn(Opcodes.IFEQ, branchLabel); + break; default: break; } @@ -507,7 +564,7 @@ public class BytecodeGenMethod implements StatementVisitor { @Override public void visit(LambdaExpression lambdaExpression) { this.lamCounter++; - + String typeErasure = "("; Iterator itr = lambdaExpression.params.iterator(); while (itr.hasNext()) { @@ -547,16 +604,31 @@ public class BytecodeGenMethod implements StatementVisitor { this.kindOfLambda = new KindOfLambda(lambdaExpression); if (kindOfLambda.isInstanceCapturingLambda()) { +// if(!kindOfLambda.getArgumentList().contains(BytecodeGen.THISTYPE)) +// kindOfLambda.getArgumentList().add(0, BytecodeGen.THISTYPE); mv.visitVarInsn(Opcodes.ALOAD, 0); + for(String v : kindOfLambda.getUsedVars()) { + mv.visitVarInsn(Opcodes.ALOAD, paramsAndLocals.get(v)); + } staticOrSpecial = Opcodes.H_INVOKESPECIAL; indexOfFirstParamLam = 1; } else { staticOrSpecial = Opcodes.H_INVOKESTATIC; staticOrInstance = Opcodes.ACC_STATIC; } - + String newDesc = "("; + int pos = 0; + if(kindOfLambda.isHasThis()) { + pos = 1; + } + + for(int i=pos;i usedVars = kindOfLambda.getUsedVars(); + + new BytecodeGenMethod(lambdaExpression, usedVars,this.resultSet, mvLambdaBody, indexOfFirstParamLam, isInterface, + classFiles,this.path, lamCounter, sf); mvLambdaBody.visitMaxs(0, 0); mvLambdaBody.visitEnd(); @@ -641,7 +715,10 @@ public class BytecodeGenMethod implements StatementVisitor { if (!fieldVar.receiver.getClass().equals(StaticClassName.class)) { mv.visitFieldInsn(Opcodes.GETFIELD, getResolvedType(fieldVar.receiver.getType()), fieldName, fieldDesc); } - + + if (isBinaryExp) { + doUnboxing(getResolvedType(fieldVar.getType())); + } // mv.visitFieldInsn(Opcodes.GETSTATIC, // fieldVar.receiver.getType().toString().replace(".", "/"), // fieldVar.fieldVarName, fieldVar.getType().toString()); @@ -794,10 +871,12 @@ public class BytecodeGenMethod implements StatementVisitor { if(methodRefl != null && !methodRefl.getReturnType().isPrimitive()) { if(methodRefl.getReturnType().equals(Object.class)) { String checkCast = getResolvedType(methodCall.getType()); - int pos = checkCast.length(); - if(checkCast.contains("<")) - pos = checkCast.indexOf("<"); - mv.visitTypeInsn(Opcodes.CHECKCAST,checkCast.substring(0,pos)); + if(!checkCast.contains("TPH ")) { + int pos = checkCast.length(); + if(checkCast.contains("<")) + pos = checkCast.indexOf("<"); + mv.visitTypeInsn(Opcodes.CHECKCAST,checkCast.substring(0,pos)); + } } if(isBinaryExp) doUnboxing(getResolvedType(methodCall.getType())); @@ -850,11 +929,13 @@ public class BytecodeGenMethod implements StatementVisitor { // methCallType = "L"+methCallType+";"; // } for(java.lang.reflect.Method m : methods) { - if(name.equals(m.getName()) && i == m.getParameterCount() && methCallType.equals(m.getReturnType().getName().replace(".", "/"))) { + if(name.equals(m.getName()) && i == m.getParameterCount() && + (methCallType.equals(m.getReturnType().getName().replace(".", "/")) || + m.getReturnType().getName().replace(".", "/").equals(Type.getInternalName(Object.class)))) { boolean typesEqual = true; Class[] pTypes = m.getParameterTypes(); for(int j = 0; j argumentList = new ArrayList<>(); + private ArrayList usedVars = new ArrayList<>(); + private boolean hasThis = false; + private ArrayList definedLocals = new ArrayList<>(); public KindOfLambda(LambdaExpression lambdaExpression) { + this.params = lambdaExpression.params; lambdaExpression.methodBody.accept(this); } + public ArrayList getUsedVars() { + return usedVars; + } + public boolean isInstanceCapturingLambda() { return this.isInstanceCapturingLambda; } @@ -28,6 +40,10 @@ public class KindOfLambda implements StatementVisitor{ return argumentList; } + public boolean isHasThis() { + return hasThis; + } + @Override public void visit(ArgumentList argumentList) { // TODO Auto-generated method stub @@ -95,14 +111,31 @@ public class KindOfLambda implements StatementVisitor{ @Override public void visit(LocalVar localVar) { - // TODO Auto-generated method stub - + if(!contain(params, localVar.name) && !definedLocals.contains(localVar.name)) { + argumentList.add(localVar.getType()); + if(hasThis) { + usedVars.add(1, localVar.name); + } else { + usedVars.add(0, localVar.name); + } + if(!isInstanceCapturingLambda) + isInstanceCapturingLambda=true; + } + } + + private boolean contain(ParameterList params2, String name) { + Iterator itr = params2.iterator(); + while(itr.hasNext()) { + FormalParameter fp = itr.next(); + if(fp.getName().equals(name)) + return true; + } + return false; } @Override public void visit(LocalVarDecl localVarDecl) { - // TODO Auto-generated method stub - + definedLocals.add(localVarDecl.getName()); } @Override @@ -157,9 +190,13 @@ public class KindOfLambda implements StatementVisitor{ @Override public void visit(This aThis) { + if(!hasThis) { + hasThis = true; + this.argumentList.add(0,aThis.getType()); + } if(!isInstanceCapturingLambda) { this.isInstanceCapturingLambda = true; - this.argumentList.add(aThis.getType()); + } } diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java index 99ec3163..7175f108 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java @@ -8,14 +8,14 @@ import de.dhbwstuttgart.typeinference.result.GenericInsertPair; public class MethodAndTPH { private String name; - private final ArrayList tphs = new ArrayList<>(); + private final ArrayList tphs = new ArrayList<>(); private final ArrayList pairs = new ArrayList<>(); public MethodAndTPH(String name) { this.name = name; } - public ArrayList getTphs() { + public ArrayList getTphs() { return tphs; } diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/Simplify.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/Simplify.java index 566eca81..2ec212f7 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/Simplify.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/Simplify.java @@ -7,7 +7,7 @@ import java.util.LinkedList; import org.objectweb.asm.Type; -import de.dhbwstuttgart.bytecode.BytecodeGen.TPHExtractor; +import de.dhbwstuttgart.bytecode.TPHExtractor; import de.dhbwstuttgart.bytecode.constraint.ExtendsConstraint; import de.dhbwstuttgart.bytecode.constraint.TPHConstraint; import de.dhbwstuttgart.bytecode.constraint.TPHConstraint.Relation; @@ -16,7 +16,7 @@ import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; public class Simplify { public static HashMap> simplifyConstraints(String name, TPHExtractor tphExtractor) { - // 1. check if there are any cycles like L set L=R and: // * remove both constraints // * substitute L with R in all constraint @@ -28,8 +28,10 @@ public class Simplify { // b) no // 3. is + // all constraints that will be simplified ArrayList allCons = tphExtractor.allCons; ArrayList consToRemove = new ArrayList<>(); + // step 1: for(TPHConstraint c : allCons) { @@ -39,12 +41,16 @@ public class Simplify { TPHConstraint revCon = getReverseConstraint(allCons,left,right); if(revCon != null) { revCon.setRel(Relation.EQUAL); + // the reverse constraint is removed because + // otherwise there is twice the same constraint + // (e.g. A A=B and B=A) consToRemove.add(revCon); c.setRel(Relation.EQUAL); substituteTPH(allCons,left, right); } } } + System.out.println(); System.out.println("NEW ALL CONST: " + allCons.size()); allCons.forEach(c->System.out.println(c.toString())); @@ -59,17 +65,99 @@ public class Simplify { System.out.println("----------------"); HashMap> result = new HashMap<>(); + // check if there is any long cycle (e.g. A allTypes = new LinkedList<>(); + // we will put all constraints which are in the cycle, in this ArrayList. + // Later these contraints will be converted to equal-constraints + ArrayList constraints = new ArrayList<>(size); + int visited = 0; + + // contains all constraints + HashMap ss1 = new HashMap<>(); + + for(TPHConstraint constr : allCons) { + ss1.put(constr.getLeft(), constr.getRight()); + } + + for(TPHConstraint c : allCons) { + + if(visited >= size) + break; + // Only extends-constraints will be checked + if(c.getRel() == Relation.EXTENDS) { + ++visited; + + String left = c.getLeft(); + String right = c.getRight(); + // put the types in linked list + allTypes.add(left); + allTypes.add(right); + + constraints.add(c); + + boolean isCycle = false; + + // iterate through the map to check if there is a cycle + while(ss1.containsKey(right)) { + ++visited; + String oldRight = right; + right = ss1.get(right); + + TPHConstraint toAdd = getConstraint(oldRight, right, allCons); + + if(toAdd != null) + constraints.add(toAdd); + + if(left.equals(right)) { + isCycle = true; + break; + } + + allTypes.add(right); + } + + if(isCycle) { + // convert all constraints to equal constraints + setAllEqual(constraints); + // these constraints will be removed from allCons + consToRemove.addAll(constraints); + // all equal types will be substitute with one type + substituteAllTPH(allCons,constraints,left); + + HashSet eq = new HashSet<>(); + // put all equal types in a set + for(String t:allTypes) { + eq.add(t); + } + // generate a new constraint (left < Object) + TPHConstraint constraint = new ExtendsConstraint(left, Type.getInternalName(Object.class), Relation.EXTENDS); + // put the generated constraint and its equal set into result set + result.put(constraint, eq); + constraints.clear(); + } + allTypes.clear(); + } + } + // build an equal set that contains all types + // which are equal and for each equal constraint put left side and right side + // in this set Then generate a constraint type < Object and put it + // with the equal set into the result. for(TPHConstraint c : allCons) { if(c.getRel()==Relation.EQUAL) { - HashSet equalTPHs = getEqualsTPHs(result, c); - TPHConstraint constraint = getKeyConstraint(result,c); - equalTPHs.add(c.getLeft()); - equalTPHs.add(c.getRight()); - result.put(constraint, equalTPHs); + if(!isTPHInResEqual(result, c.getLeft())) { + HashSet equalTPHs = getEqualsTPHs(result, c); + TPHConstraint constraint = getKeyConstraint(result,c); + equalTPHs.add(c.getLeft()); + equalTPHs.add(c.getRight()); + result.put(constraint, equalTPHs); + } consToRemove.add(c); size--; } } + System.out.println("Step 2 Result: "); result.forEach((c,hs)->{ System.out.print(c.toString() + " -> "); @@ -79,7 +167,9 @@ public class Simplify { System.out.println(); }); System.out.println("----------------"); + // remove all equal-constraints allCons.removeAll(consToRemove); + // add all generated constraints to allCons allCons.addAll(result.keySet()); if(!allCons.isEmpty() && allCons.size()<2) { @@ -91,19 +181,23 @@ public class Simplify { } size += result.keySet().size(); - + // all constraints which have Object on the right side will + // be ignored, because they are simplified and can not be changed. for(TPHConstraint c : allCons) { if(c.getRight().equals(Type.getInternalName(Object.class))) size--; } - ArrayList methodTphs = new ArrayList<>(); + // get all tph of the method + ArrayList methodTphs = new ArrayList<>(); for(MethodAndTPH m : tphExtractor.ListOfMethodsAndTph) { if(m.getName().equals(name)) { methodTphs = m.getTphs(); break; } } - + // check if there are multiple constraint with the same left side. + // if yes => check if the super type in the method, if not + // then ignore it. HashMap subAndSuper = new HashMap<>(); for(TPHConstraint c : allCons) { if(subAndSuper.containsKey(c.getLeft())) { @@ -155,6 +249,8 @@ public class Simplify { // Die größte Supertype String superTphRes = tphInRel.getLast(); + // if there is any constraint X < subTph, then + // add X at the beginning of the list. while(subAndSuper.containsValue(subTphRes)) { for(String tph : subAndSuper.keySet()) { if(containTPH(methodTphs,tph) && subAndSuper.get(tph).equals(subTphRes)) { @@ -165,12 +261,18 @@ public class Simplify { if(subTphRes.equals(tphInRel.getFirst())) { break; } + + if(isTPHInConstraint(result, subTphRes)) + break; + tphInRel.addFirst(subTphRes); numOfVisitedPairs++; } subTphRes = tphInRel.getFirst(); - + // if the last type in the list not a type in method-types + // then find the last type in front of this type, which is + // a type in method-types int i = 2; while(!containTPH(methodTphs,superTphRes) && (tphInRel.size()-i) >0) { superTphRes = tphInRel.get(tphInRel.size()-i); @@ -181,13 +283,14 @@ public class Simplify { result.put(new ExtendsConstraint(subTphRes, Type.getInternalName(Object.class), Relation.EXTENDS), null); } else { result.put(new ExtendsConstraint(subTphRes, superTphRes, Relation.EXTENDS), null); - result.put(new ExtendsConstraint(superTphRes, Type.getInternalName(Object.class), Relation.EXTENDS), null); + if(!isTPHInConstraint(result, superTphRes)) + result.put(new ExtendsConstraint(superTphRes, Type.getInternalName(Object.class), Relation.EXTENDS), null); } } - for(TypePlaceholder tph : methodTphs) { - if(!isTPHInConstraint(result, tph.getName())) { - result.put(new ExtendsConstraint(tph.getName(), Type.getInternalName(Object.class), Relation.EXTENDS), null); + for(String tph : methodTphs) { + if(!isTPHInConstraint(result, tph)) { + result.put(new ExtendsConstraint(tph, Type.getInternalName(Object.class), Relation.EXTENDS), null); } } @@ -211,6 +314,44 @@ public class Simplify { return result; } + private static TPHConstraint getConstraint(String oldRight, String right, ArrayList allCons) { + for(TPHConstraint c : allCons) { + if(c.getLeft().equals(oldRight) && c.getRight().equals(right)) + return c; + } + return null; + } + + private static boolean isTPHInResEqual(HashMap> result, String left) { + for(HashSet eq : result.values()) { + if(eq.contains(left)) { + return true; + } + } + return false; + } + + private static void substituteAllTPH(ArrayList allCons, ArrayList constraints, + String first) { + for(TPHConstraint c : allCons) { + for(TPHConstraint c2 : constraints) { + if(c.getRel() == Relation.EXTENDS) { + if(c2.getLeft().equals(c.getLeft()) || c2.getRight().equals(c.getLeft())) + c.setLeft(first); + if(c2.getLeft().equals(c.getRight()) || c2.getRight().equals(c.getRight())) + c.setRight(first); + } + + } + } + } + + private static void setAllEqual(ArrayList constraints) { + for(TPHConstraint c:constraints) { + c.setRel(Relation.EQUAL); + } + } + public static HashMap> simplifyContraints(HashMap> allConstraints) { // 1. check if there are any cycles like L set L=R and: @@ -406,9 +547,9 @@ public class Simplify { return false; } - private static boolean containTPH(ArrayList methodTphs, String sub) { - for(TypePlaceholder tph : methodTphs) { - if(tph.getName().equals(sub)) + private static boolean containTPH(ArrayList methodTphs, String sub) { + for(String tph : methodTphs) { + if(tph.equals(sub)) return true; } return false; diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index 9049051c..8cc98b6a 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -119,21 +119,37 @@ public class JavaTXCompiler { TypeUnify unify = new TypeUnify(); Set> results = new HashSet<>(); - Set>> cardProd = unifyCons.cartesianProduct(); - for (List> xCons : cardProd ){ - Set xConsSet = new HashSet<>(); - for (Constraint constraint : xCons) { - xConsSet.addAll(constraint); - } - //.collect(Collectors.toCollection(ArrayList::new)))) - System.out.println(xConsSet); - Set paraTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().map(y -> y.getParameterList().getFormalparalist() + try { + //FileWriter logFile = new FileWriter(new File(System.getProperty("user.dir")+"/test/logFiles/"+"log")); + //logFile.write("FC:\\" + finiteClosure.toString()+"\n"); + //for(SourceFile sf : this.sourceFiles.values()) { + // logFile.write(ASTTypePrinter.print(sf)); + //} + //logFile.flush(); + Set>> cardProd = unifyCons.cartesianProduct(); + for (List> xCons : cardProd ){ + Set xConsSet = new HashSet<>(); + for (Constraint constraint : xCons) { + xConsSet.addAll(constraint); + } + //.collect(Collectors.toCollection(ArrayList::new)))) + System.out.println(xConsSet); + Set methodParaTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().map(y -> y.getParameterList().getFormalparalist() .stream().filter(z -> z.getType() instanceof TypePlaceholder) .map(z -> ((TypePlaceholder)z.getType()).getName()).collect(Collectors.toCollection(HashSet::new))) .reduce(new HashSet(), (a,b) -> { a.addAll(b); return a;}, (a,b) -> { a.addAll(b); return a;} ) ) .reduce(new HashSet(), (a,b) -> { a.addAll(b); return a;} ); - Set returnTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder) + Set constructorParaTypeVarNames = allClasses.stream().map(x -> x.getConstructors().stream().map(y -> y.getParameterList().getFormalparalist() + .stream().filter(z -> z.getType() instanceof TypePlaceholder) + .map(z -> ((TypePlaceholder)z.getType()).getName()).collect(Collectors.toCollection(HashSet::new))) + .reduce(new HashSet(), (a,b) -> { a.addAll(b); return a;}, (a,b) -> { a.addAll(b); return a;} ) ) + .reduce(new HashSet(), (a,b) -> { a.addAll(b); return a;} ); + + Set paraTypeVarNames = methodParaTypeVarNames; + paraTypeVarNames.addAll(constructorParaTypeVarNames); + + Set returnTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder) .map(z -> ((TypePlaceholder)z.getReturnType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce((a,b) -> { a.addAll(b); return a;} ).get(); Set fieldTypeVarNames = allClasses.stream().map(x -> x.getFieldDecl().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder) diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java index b0331a00..a945b02a 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java @@ -151,7 +151,7 @@ public class SyntaxTreeGenerator{ block = stmtGen.convert(body.block(),true); } if(parentClass.equals(new JavaClassName(name))){ - return new Constructor(modifiers, name, retType, parameterList, block, gtvDeclarations, header.getStart(), fieldInitializations); + return new Constructor(modifiers, name, retType, parameterList, block, gtvDeclarations, header.getStart() /*, fieldInitializations geloescht PL 2018-11-24 */); }else{ return new Method(modifiers, name, retType, parameterList,block, gtvDeclarations, header.getStart()); } @@ -198,14 +198,18 @@ public class SyntaxTreeGenerator{ } List fielddecl = convertFields(ctx.classBody(), generics); //fieldInitializations = generateFieldInitializations(ctx.classBody(), generics); - List methods = convertMethods(ctx.classBody(), name, superClass, generics); + List methodsAndConstructors = convertMethods(ctx.classBody(), name, superClass, generics); + List methods = new ArrayList<>(); List konstruktoren = new ArrayList<>(); - for(int i = 0; i implementedInterfaces = convert(ctx.superinterfaces(), generics); - return new ClassOrInterface(modifiers, name, fielddecl, methods, konstruktoren, genericClassParameters, superClass, + + return new ClassOrInterface(modifiers, name, fielddecl, + Optional.of(this.generatePseudoConstructor(ctx.Identifier().getText(), name, superClass, genericClassParameters, offset)), + methods, konstruktoren, genericClassParameters, superClass, isInterface, implementedInterfaces, offset); } @@ -267,8 +274,16 @@ public class SyntaxTreeGenerator{ RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), classGenerics, offset); ParameterList params = new ParameterList(new ArrayList<>(), offset); Block block = new Block(new ArrayList<>(), offset); - return new Constructor(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset, fieldInitializations); + return new Constructor(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset /*, fieldInitializations geloescht PL 2018-11-24 */); } + + /* fieldInitializations werden in einem Psedokonstruktor in der abstrakten Syntax gespeichert */ + private Constructor generatePseudoConstructor(String className, JavaClassName parentClass, RefType superClass, GenericDeclarationList classGenerics, Token offset){ + RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), classGenerics, offset); + ParameterList params = new ParameterList(new ArrayList<>(), offset); + Block block = new Block(new ArrayList<>(fieldInitializations), offset); + return new Constructor(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset /*, fieldInitializations geloescht PL 2018-11-24 */); + } private RefType convert(Java8Parser.SuperclassContext superclass) { if(superclass.classType().classOrInterfaceType() != null){ @@ -441,7 +456,7 @@ public class SyntaxTreeGenerator{ List extendedInterfaces = convert(ctx.extendsInterfaces(), generics); - return new ClassOrInterface(modifiers, name, fields, methods, new ArrayList<>(), + return new ClassOrInterface(modifiers, name, fields, Optional.empty(), methods, new ArrayList<>(), genericParams, superClass, true, extendedInterfaces, ctx.getStart()); } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java b/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java index d0177ace..bbd184f0 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java @@ -3,6 +3,7 @@ package de.dhbwstuttgart.syntaxtree; import de.dhbwstuttgart.core.IItemWithOffset; import de.dhbwstuttgart.exceptions.DebugException; import de.dhbwstuttgart.parser.scope.JavaClassName; +import de.dhbwstuttgart.syntaxtree.statement.Statement; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter; @@ -16,6 +17,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Optional; /** * Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces @@ -24,6 +26,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{ protected int modifiers; protected JavaClassName name; private List fields = new ArrayList<>(); + private Optional fieldInitializations; //PL 2018-11-24: Noetig, um Bytecode fuer initializators nur einmal zu erzeugen private List methods = new ArrayList<>(); private GenericDeclarationList genericClassParameters; private RefType superClass; @@ -31,13 +34,14 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{ private List implementedInterfaces; private List constructors; - public ClassOrInterface(int modifiers, JavaClassName name, List fielddecl, List methods, List constructors, GenericDeclarationList genericClassParameters, + public ClassOrInterface(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List implementedInterfaces, Token offset){ super(offset); if(isInterface && !Modifier.isInterface(modifiers))modifiers += Modifier.INTERFACE; this.modifiers = modifiers; this.name = name; this.fields = fielddecl; + this.fieldInitializations= fieldInitializations; this.genericClassParameters = genericClassParameters; this.superClass = superClass; this.isInterface = isInterface; @@ -59,6 +63,11 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{ public List getFieldDecl(){ return this.fields; } + + public Optional getfieldInitializations(){ + return this.fieldInitializations; + } + public List getMethods(){ return this.methods; } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/Constructor.java b/src/main/java/de/dhbwstuttgart/syntaxtree/Constructor.java index 79db5ced..8be687f8 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/Constructor.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/Constructor.java @@ -15,8 +15,8 @@ public class Constructor extends Method { //TODO: Constructor braucht ein super-Statement public Constructor(int modifier, String name, RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList parameterList, Block codeInsideConstructor, - GenericDeclarationList gtvDeclarations, Token offset, List fieldInitializations) { - super(modifier, name, returnType, parameterList, prepareBlock(codeInsideConstructor,fieldInitializations), gtvDeclarations, offset); + GenericDeclarationList gtvDeclarations, Token offset /*, List fieldInitializations geloescht PL 2018-11-24 */) { + super(modifier, name, returnType, parameterList, /*codeInsideConstructor,*/ prepareBlock(codeInsideConstructor ) /*,fieldInitializations )geloescht PL 2018-11-24 )*/, gtvDeclarations, offset); } @@ -25,10 +25,10 @@ public class Constructor extends Method { * welche die Felder der zugehörigen Klasse dieses * Konstruktor initialisieren */ - protected static Block prepareBlock(Block constructorBlock, List fieldInitializations){ + protected static Block prepareBlock(Block constructorBlock /*, List fieldInitializations new ArrayList<>() geloescht PL 2018-11-24 */){ List statements = constructorBlock.getStatements(); statements.add(0, new SuperCall(constructorBlock.getOffset())); - statements.addAll(fieldInitializations); + /* statements.addAll(fieldInitializations); geloescht PL 2018-11-24 */ return new Block(statements, constructorBlock.getOffset()); } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java index d92d0b9a..2fb32dbe 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java @@ -4,6 +4,7 @@ import java.lang.reflect.*; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.parser.NullToken; @@ -65,7 +66,7 @@ public class ASTFactory { Token offset = new NullToken(); //Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde - return new ClassOrInterface(modifier, name, felder, methoden, konstruktoren, genericDeclarationList, superClass,isInterface, implementedInterfaces, offset); + return new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */,methoden, konstruktoren, genericDeclarationList, superClass,isInterface, implementedInterfaces, offset); } private static Field createField(java.lang.reflect.Field field, JavaClassName jreClass) { @@ -98,7 +99,7 @@ public class ASTFactory { return null; } - return new de.dhbwstuttgart.syntaxtree.Constructor(modifier, name,returnType, parameterList, block, gtvDeclarations, offset, new ArrayList<>()); + return 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){ diff --git a/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java b/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java index 0c8220f1..6067851e 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java @@ -17,10 +17,11 @@ import org.antlr.v4.runtime.Token; import java.util.ArrayList; import java.util.List; +import java.util.Optional; public class FunNClass extends ClassOrInterface { public FunNClass(List funNParams) { - super(0, new JavaClassName("Fun"+(funNParams.size())), new ArrayList<>(), + super(0, new JavaClassName("Fun"+(funNParams.size())), new ArrayList<>(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, new ArrayList<>(), new NullToken()); diff --git a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java index 6a441050..246c3691 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java @@ -38,6 +38,9 @@ public class TYPE { for(Constructor m : cl.getConstructors()){ ret.addAll(getConstraintsConstructor(m,info, cl)); } + if (cl.getfieldInitializations().isPresent()) { + ret.addAll(getConstraintsConstructor(cl.getfieldInitializations().get(), info, cl)); + } return ret; } /* @@ -61,6 +64,7 @@ public class TYPE { return new TypeInferenceInformation(classes); } */ + private ConstraintSet getConstraintsMethod(Method m, TypeInferenceInformation info, ClassOrInterface currentClass) { if(m.block == null)return new ConstraintSet(); //Abstrakte Methoden generieren keine Constraints TypeInferenceBlockInformation blockInfo = new TypeInferenceBlockInformation(info.getAvailableClasses(), currentClass, m); diff --git a/src/test/resources/bytecode/LambdaCapturetest.java b/src/test/resources/bytecode/LambdaCapturetest.java new file mode 100644 index 00000000..438c2315 --- /dev/null +++ b/src/test/resources/bytecode/LambdaCapturetest.java @@ -0,0 +1,43 @@ +/** + * + */ +package bytecode; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.BeforeClass; +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +/** + * @author fayez + * + */ +public class LambdaCapturetest { + private static String path; + private static File fileToTest; + private static JavaTXCompiler compiler; + private static ClassLoader loader; + private static Class classToTest; + private static String pathToClassFile; + private static Object instanceOfClass; + + @Test + public void generateBC() throws Exception { + path = System.getProperty("user.dir")+"/test/bytecode/javFiles/LambdaCapture.jav"; + fileToTest = new File(path); + compiler = new JavaTXCompiler(fileToTest); + compiler.generateBytecode(System.getProperty("user.dir")+"/testBytecode/generatedBC/"); + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("LambdaCapture"); + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + } + +} diff --git a/src/test/resources/bytecode/simplifyalgo/CycleTest.java b/src/test/resources/bytecode/simplifyalgo/CycleTest.java new file mode 100644 index 00000000..88697e6d --- /dev/null +++ b/src/test/resources/bytecode/simplifyalgo/CycleTest.java @@ -0,0 +1,76 @@ +/** + * + */ +package bytecode.simplifyalgo; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import java.util.HashSet; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.objectweb.asm.Type; + +import de.dhbwstuttgart.bytecode.TPHExtractor; +import de.dhbwstuttgart.bytecode.constraint.ExtendsConstraint; +import de.dhbwstuttgart.bytecode.constraint.TPHConstraint; +import de.dhbwstuttgart.bytecode.constraint.TPHConstraint.Relation; +import de.dhbwstuttgart.bytecode.utilities.MethodAndTPH; +import de.dhbwstuttgart.bytecode.utilities.Simplify; + +/** + * @author Fayez Abu Alia + * + */ +public class CycleTest { + + private static TPHExtractor tphExtractor; + private static String methName; + + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + tphExtractor = new TPHExtractor(); + // A < B + TPHConstraint c1 = new ExtendsConstraint("A", "B", Relation.EXTENDS); + // B < C + TPHConstraint c2 = new ExtendsConstraint("B", "C", Relation.EXTENDS); + // C < D + TPHConstraint c3 = new ExtendsConstraint("C", "D", Relation.EXTENDS); + // D < A + TPHConstraint c4 = new ExtendsConstraint("D", "A", Relation.EXTENDS); + // name + methName = "m"; + MethodAndTPH mtph = new MethodAndTPH("m"); + mtph.getTphs().add("A"); + mtph.getTphs().add("B"); + mtph.getTphs().add("C"); + mtph.getTphs().add("D"); + tphExtractor.ListOfMethodsAndTph.add(mtph); + tphExtractor.allCons.add(c1); + tphExtractor.allCons.add(c2); + tphExtractor.allCons.add(c3); + tphExtractor.allCons.add(c4); + + } + + @Test + public void test() { + HashMap> result = new HashMap<>(); + HashSet equals = new HashSet<>(); + equals.add("A"); + equals.add("B"); + equals.add("C"); + equals.add("D"); + TPHConstraint k = new ExtendsConstraint("A", Type.getInternalName(Object.class), Relation.EXTENDS); + result.put(k, equals); + + HashMap> sim = Simplify.simplifyConstraints(methName, tphExtractor); + boolean areEquals = SimpleCycle.areMapsEqual(result, sim); + assertTrue(areEquals); + } + +} diff --git a/src/test/resources/bytecode/simplifyalgo/SameLeftSide.java b/src/test/resources/bytecode/simplifyalgo/SameLeftSide.java new file mode 100644 index 00000000..b5c4e875 --- /dev/null +++ b/src/test/resources/bytecode/simplifyalgo/SameLeftSide.java @@ -0,0 +1,97 @@ +package bytecode.simplifyalgo; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import java.util.HashSet; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.objectweb.asm.Type; + +import de.dhbwstuttgart.bytecode.TPHExtractor; +import de.dhbwstuttgart.bytecode.constraint.ExtendsConstraint; +import de.dhbwstuttgart.bytecode.constraint.TPHConstraint; +import de.dhbwstuttgart.bytecode.constraint.TPHConstraint.Relation; +import de.dhbwstuttgart.bytecode.utilities.MethodAndTPH; +import de.dhbwstuttgart.bytecode.utilities.Simplify; +import de.dhbwstuttgart.typedeployment.TypeInsertPlacer; + +/** +* +* @author Fayez Abu Alia +* +*/ +public class SameLeftSide { + // Typeplaceholders können nicht definiert werden, da die Konstruktor + // private ist => Test geht nicht + private static TPHExtractor tphExtractor; + private static String methName; + private static String methName2; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + tphExtractor = new TPHExtractor(); + // A < B + TPHConstraint c1 = new ExtendsConstraint("A", "B", Relation.EXTENDS); + // A < C + TPHConstraint c2 = new ExtendsConstraint("A", "C", Relation.EXTENDS); + // B < D + TPHConstraint c3 = new ExtendsConstraint("B", "D", Relation.EXTENDS); + // C < E + TPHConstraint c4 = new ExtendsConstraint("C", "E", Relation.EXTENDS); + // name + methName = "m1"; + MethodAndTPH m1 = new MethodAndTPH("m1"); + + methName2 = "m2"; + MethodAndTPH m2 = new MethodAndTPH("m2"); + + m1.getTphs().add("A"); + m1.getTphs().add("B"); + m1.getTphs().add("D"); + + m2.getTphs().add("C"); + m2.getTphs().add("E"); + + tphExtractor.ListOfMethodsAndTph.add(m1); + tphExtractor.ListOfMethodsAndTph.add(m2); + + tphExtractor.allCons.add(c1); + tphExtractor.allCons.add(c2); + tphExtractor.allCons.add(c3); + tphExtractor.allCons.add(c4); + } + + @Test + public void testM1() { + HashMap> result = new HashMap<>(); + + TPHConstraint d = new ExtendsConstraint("D", Type.getInternalName(Object.class), Relation.EXTENDS); + TPHConstraint a = new ExtendsConstraint("A", "D", Relation.EXTENDS); + TPHConstraint b = new ExtendsConstraint("B", "D", Relation.EXTENDS); + result.put(d, null); + result.put(a, null); + result.put(b, null); + + HashMap> sim = Simplify.simplifyConstraints(methName, tphExtractor); + boolean areEquals = SimpleCycle.areMapsEqual(result, sim); + assertTrue(areEquals); + } + + @Test + public void testM2() { + HashMap> result = new HashMap<>(); + + TPHConstraint e = new ExtendsConstraint("E", Type.getInternalName(Object.class), Relation.EXTENDS); + TPHConstraint c = new ExtendsConstraint("C", "E", Relation.EXTENDS); + + result.put(e, null); + result.put(c, null); + + HashMap> sim = Simplify.simplifyConstraints(methName2, tphExtractor); + boolean areEquals = SimpleCycle.areMapsEqual(result, sim); + assertTrue(areEquals); + } + +} diff --git a/src/test/resources/bytecode/simplifyalgo/SimpleCycle.java b/src/test/resources/bytecode/simplifyalgo/SimpleCycle.java new file mode 100644 index 00000000..636eb026 --- /dev/null +++ b/src/test/resources/bytecode/simplifyalgo/SimpleCycle.java @@ -0,0 +1,79 @@ +package bytecode.simplifyalgo; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import java.util.HashSet; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.objectweb.asm.Type; + +import de.dhbwstuttgart.bytecode.TPHExtractor; +import de.dhbwstuttgart.bytecode.constraint.ExtendsConstraint; +import de.dhbwstuttgart.bytecode.constraint.TPHConstraint; +import de.dhbwstuttgart.bytecode.constraint.TPHConstraint.Relation; +import de.dhbwstuttgart.bytecode.utilities.Simplify; +/** + * + * @author Fayez Abu Alia + * + */ +public class SimpleCycle { + private static TPHExtractor tphExtractor; + private static String methName; + @BeforeClass + public static void setUpBeforeClass() throws Exception { + tphExtractor = new TPHExtractor(); + // A < B + TPHConstraint c1 = new ExtendsConstraint("A", "B", Relation.EXTENDS); + // B < A + TPHConstraint c2 = new ExtendsConstraint("B", "A", Relation.EXTENDS); + // name + methName = "m"; + tphExtractor.allCons.add(c1); + tphExtractor.allCons.add(c2); + + } + + @Test + public void test() { + HashMap> result = new HashMap<>(); + HashSet equals = new HashSet<>(); + equals.add("A"); + equals.add("B"); + TPHConstraint k = new ExtendsConstraint("B", Type.getInternalName(Object.class), Relation.EXTENDS); + result.put(k, equals); + + HashMap> sim = Simplify.simplifyConstraints(methName, tphExtractor); + boolean areEquals = areMapsEqual(result, sim); + assertTrue(areEquals); + } + + public static boolean areMapsEqual(HashMap> m1, HashMap> m2) { + + for(TPHConstraint c : m1.keySet()) { + for(TPHConstraint c2 : m2.keySet()) { + if(c.getLeft().equals(c2.getLeft()) && c.getRight().equals(c2.getRight()) && c.getRel()==c2.getRel()) { + HashSet eq1 = m1.get(c); + HashSet eq2 = m2.get(c2); + + if((eq1 == null && eq2 != null) || (eq1 != null && eq2 == null)) + return false; + if(eq1 != null) { + if(eq1.size() != eq2.size()) + return false; + + for(String tph:eq1) { + if(!eq2.contains(tph)) + return false; + } + } + } + } + + } + return true; + } + +} diff --git a/src/test/resources/javFiles/bytecode/Faculty.jav b/src/test/resources/javFiles/bytecode/Faculty.jav index a6171e5f..2754b7f8 100644 --- a/src/test/resources/javFiles/bytecode/Faculty.jav +++ b/src/test/resources/javFiles/bytecode/Faculty.jav @@ -4,17 +4,19 @@ public class Faculty { public fact; Faculty() { fact = (x) -> { - if(x<0) { - return 0; - }else if (x < 1) { - return x; - } - else { - return x * (fact.apply(x-1)); - } - }; + if (x == 1) { + return 1; + } + else { + return x * (fact.apply(x-1)); + } + }; } + + public getFact(x) { + return fact.apply(x); + } // m (x) { // //// var fact = (x) -> { diff --git a/src/test/resources/javFiles/bytecode/LambdaCapture.jav b/src/test/resources/javFiles/bytecode/LambdaCapture.jav new file mode 100644 index 00000000..ab1751f4 --- /dev/null +++ b/src/test/resources/javFiles/bytecode/LambdaCapture.jav @@ -0,0 +1,12 @@ +import java.lang.Integer; +public class LambdaCapture { + Integer i = 8; + f; + public LambdaCapture(){ + Integer w = 7; + f = j ->{ + return w+i;}; + + } + +} \ No newline at end of file diff --git a/src/test/resources/javFiles/bytecode/OL.jav b/src/test/resources/javFiles/bytecode/OL.jav index 68650428..700e50f0 100644 --- a/src/test/resources/javFiles/bytecode/OL.jav +++ b/src/test/resources/javFiles/bytecode/OL.jav @@ -9,7 +9,7 @@ public class OL { m(x) { return x + x; } } - + public class OLMain { @@ -20,4 +20,3 @@ public class OLMain { return ol.m(x); } } - diff --git a/src/test/resources/javFiles/bytecode/Tph.jav b/src/test/resources/javFiles/bytecode/Tph.jav index 9faa570c..4a49ac46 100644 --- a/src/test/resources/javFiles/bytecode/Tph.jav +++ b/src/test/resources/javFiles/bytecode/Tph.jav @@ -2,8 +2,8 @@ public class Tph { m(a,b){ var c = m2(b); - return a; -// return m2(b); +// return a; + return m2(b); } m2(b){ diff --git a/test/bytecode/FacultyTest.java b/test/bytecode/FacultyTest.java new file mode 100644 index 00000000..c347456a --- /dev/null +++ b/test/bytecode/FacultyTest.java @@ -0,0 +1,58 @@ +package bytecode; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +public class FacultyTest { + private static String path; + private static File fileToTest; + private static JavaTXCompiler compiler; + private static ClassLoader loader; + private static Class classToTest; + private static String pathToClassFile; + private static Object instanceOfClass; + + @Test + public void generateBC() throws Exception { + path = System.getProperty("user.dir")+"/test/bytecode/javFiles/Faculty.jav"; + fileToTest = new File(path); + compiler = new JavaTXCompiler(fileToTest); + compiler.generateBytecode(System.getProperty("user.dir")+"/testBytecode/generatedBC/"); + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("Faculty"); + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + + Method getFact = classToTest.getDeclaredMethod("getFact", Integer.class); +// Field fact = classToTest.getDeclaredField("fact"); +// Class lambda = m.invoke(instanceOfClass).getClass(); +// Class lambda = fact.getType(); +// System.out.println(fact.getType().getName()); +// Method apply = lambda.getMethod("apply", Object.class); +// System.out.println(lambda.getMethods()[0]); +// System.out.println(instanceOfClass.toString()); +// // Damit man auf die Methode zugreifen kann +// apply.setAccessible(true); + // Field value +// Object fieldVal = fact.get(instanceOfClass); + Integer i = 3; +// Method applyFromField = fieldVal.getClass().getDeclaredMethod("apply", Object.class); +// applyFromField.setAccessible(true); +// Integer result = (Integer) apply.invoke(lambda,i); + Integer result = (Integer) getFact.invoke(instanceOfClass,i); + + assertEquals(6, result); + } + + +} diff --git a/test/bytecode/LambdaTest.java b/test/bytecode/LambdaTest.java new file mode 100644 index 00000000..d2e69249 --- /dev/null +++ b/test/bytecode/LambdaTest.java @@ -0,0 +1,50 @@ +package bytecode; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +public class LambdaTest { + private static String path; + private static File fileToTest; + private static JavaTXCompiler compiler; + private static ClassLoader loader; + private static Class classToTest; + private static String pathToClassFile; + private static Object instanceOfClass; + + @Test + public void generateBC() throws Exception { + path = System.getProperty("user.dir")+"/test/bytecode/javFiles/Lambda.jav"; + fileToTest = new File(path); + compiler = new JavaTXCompiler(fileToTest); + compiler.generateBytecode(System.getProperty("user.dir")+"/testBytecode/generatedBC/"); + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("Lambda"); + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + + Method m = classToTest.getDeclaredMethod("m"); + Class lambda = m.invoke(instanceOfClass).getClass(); + Method apply = lambda.getMethod("apply", Object.class); + + // Damit man auf die Methode zugreifen kann + apply.setAccessible(true); + + Integer i = 77; + System.out.println(m.invoke(instanceOfClass).toString()); + Integer result = (Integer) apply.invoke(m.invoke(instanceOfClass), i); + + assertEquals(77, result); + } + + +} diff --git a/test/bytecode/MatrixOpTest.java b/test/bytecode/MatrixOpTest.java new file mode 100644 index 00000000..178aa43e --- /dev/null +++ b/test/bytecode/MatrixOpTest.java @@ -0,0 +1,91 @@ +package bytecode; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Vector; + +import org.junit.BeforeClass; +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +public class MatrixOpTest { + private static String path; + private static File fileToTest; + private static JavaTXCompiler compiler; + private static ClassLoader loader; + private static Class classToTest; + private static String pathToClassFile; + private static Object instanceOfClass_m1; + private static Object instanceOfClass_m2; + private static Object instanceOfClass_m3; + + @Test + public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IOException, InstantiationException { + path = System.getProperty("user.dir")+"/test/bytecode/javFiles/MatrixOP.jav"; + fileToTest = new File(path); + compiler = new JavaTXCompiler(fileToTest); + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; + compiler.generateBytecode(pathToClassFile); + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("MatrixOP"); +/* + Vector> vv = new Vector>(); + Vector v1 = new Vector (); + v1.addElement(2); + v1.addElement(2); + Vector v2 = new Vector (); + v2.addElement(3); + v2.addElement(3); + //Matrix m1 = new Matrix(); + //m1.addElement(v1); + //m1.addElement(v2); + vv.addElement(v1); + vv.addElement(v2); + instanceOfClass_m1 = classToTest.getDeclaredConstructor(Vector.class).newInstance(vv); //Matrix m1 = new Matrix(vv); + + Vector> vv1 = new Vector>(); + Vector v3 = new Vector (); + v3.addElement(2); + v3.addElement(2); + Vector v4 = new Vector (); + v4.addElement(3); + v4.addElement(3); + //Matrix m2 = new Matrix(); + //m2.addElement(v3); + //m2.addElement(v4); + vv1.addElement(v3); + vv1.addElement(v4); + instanceOfClass_m2 = classToTest.getDeclaredConstructor(Vector.class).newInstance(vv1);//Matrix m2 = new Matrix(vv1); + + + + //Matrix m3 = m1.mul(vv1); + Method mul = classToTest.getDeclaredMethod("mul", Vector.class); + Object result = mul.invoke(instanceOfClass_m1, instanceOfClass_m2); + System.out.println(instanceOfClass_m1.toString() + " * " + instanceOfClass_m2.toString() + " = " + result.toString()); + + Vector> res = new Vector>(); + Vector v5 = new Vector (); + v5.addElement(10); + v5.addElement(10); + Vector v6 = new Vector (); + v6.addElement(15); + v6.addElement(15); + //Matrix m2 = new Matrix(); + //m2.addElement(v3); + //m2.addElement(v4); + res.addElement(v5); + res.addElement(v6); + instanceOfClass_m3 = classToTest.getDeclaredConstructor(Vector.class).newInstance(res); + assertEquals(result, instanceOfClass_m3); +*/ + } + +} diff --git a/test/bytecode/YTest.java b/test/bytecode/YTest.java new file mode 100644 index 00000000..1c4f13a6 --- /dev/null +++ b/test/bytecode/YTest.java @@ -0,0 +1,52 @@ +package bytecode; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +public class YTest { + private static String path; + private static File fileToTest; + private static JavaTXCompiler compiler; + private static ClassLoader loader; + private static Class classToTest; + private static String pathToClassFile; + private static Object instanceOfClass; + + @Test + public void generateBC() throws Exception { + path = System.getProperty("user.dir")+"/test/bytecode/javFiles/Y.jav"; + fileToTest = new File(path); +// compiler = new JavaTXCompiler(fileToTest); +// compiler.generateBytecode(System.getProperty("user.dir")+"/testBytecode/generatedBC/"); +// pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; +// loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); +// classToTest = loader.loadClass("Y"); + /* + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + + Method m = classToTest.getDeclaredMethod("m"); + Class lambda = m.invoke(instanceOfClass).getClass(); + Method apply = lambda.getMethod("apply", Object.class); + + // Damit man auf die Methode zugreifen kann + apply.setAccessible(true); + + Integer i = 77; + + Integer result = (Integer) apply.invoke(m.invoke(instanceOfClass), i); + + assertEquals(77, result); + */ + } + + +}