From 73f412d22d1e30e8612f16914e60ec7dea3a67f4 Mon Sep 17 00:00:00 2001
From: Fayez Abu Alia <fayez.abu-alia@student.uni-tuebingen.de>
Date: Fri, 26 Apr 2019 11:56:58 +0200
Subject: [PATCH] Klassendatei fuer FunN beim Methodaufruf wird erzeugt, wenn
 der Receiver den Typ FunN besitzt. Die Loesung vom Duplicate Field Problem
 wird angepasst.

---
 .../dhbwstuttgart/bytecode/BytecodeGen.java   | 435 +++++++++---------
 .../bytecode/BytecodeGenMethod.java           |  35 +-
 .../bytecode/signature/Signature.java         |   6 +-
 .../bytecode/utilities/MethodCallHelper.java  |  72 ++-
 .../utilities/MethodFromMethodCall.java       |   1 +
 5 files changed, 310 insertions(+), 239 deletions(-)

diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java
index e721fd9f..0ff140b3 100644
--- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java
+++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java
@@ -46,11 +46,11 @@ import de.dhbwstuttgart.typeinference.result.ResultPair;
 import de.dhbwstuttgart.typeinference.result.ResultSet;
 
 public class BytecodeGen implements ASTVisitor {
-	
-	ClassWriter cw =new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
-	
+
+	ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+
 	String type;
-	
+
 	public static RefTypeOrTPHOrWildcardOrGeneric THISTYPE = null;
 	String className;
 	private boolean isInterface;
@@ -58,35 +58,38 @@ public class BytecodeGen implements ASTVisitor {
 	private ResultSet resultSet;
 	private SourceFile sf;
 	private String path;
-	
+
 	private Optional<Constructor> fieldInitializations;
-	
+
 	private int indexOfFirstParam = 0;
-	
+
 	private String superClass;
-	
+
 	private ArrayList<String> tphsClass;
-	
-	// stores parameter, local vars and the next index on the local variable table, which use for aload_i, astore_i,...
+
+	// stores parameter, local vars and the next index on the local variable table,
+	// which use for aload_i, astore_i,...
 	HashMap<String, Integer> paramsAndLocals = new HashMap<>();
 	// stores generics and their bounds of class
 	HashMap<String, String> genericsAndBounds = new HashMap<>();
-	
+
 	private int constructorPos = 0;
-	
+
 	private final TPHExtractor tphExtractor = new TPHExtractor();
 	private final ArrayList<GenericInsertPair> commonPairs = new ArrayList<>();
-	
-	HashMap<String,RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes = new HashMap<>();
+
+	HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes = new HashMap<>();
 	byte[] bytecode;
-	HashMap<String,byte[]> classFiles;
-	
+	HashMap<String, byte[]> classFiles;
+
 	private final ArrayList<String> methodNameAndParamsT = new ArrayList<>();
 	private final ArrayList<String> fieldNameAndParamsT = new ArrayList<>();
-	
+
 	private HashMap<String, SimplifyResult> simplifyResults = new HashMap<>();
 	private List<HashMap<String, SimplifyResult>> simplifyResultsList = new ArrayList<>();
-	
+
+	private final ArrayList<String> fieldNameSignature = new ArrayList<>();
+
 	public List<HashMap<String, SimplifyResult>> getSimplifyResultsList() {
 		return simplifyResultsList;
 	}
@@ -95,16 +98,17 @@ public class BytecodeGen implements ASTVisitor {
 		this.simplifyResultsList = simplifyResultsList;
 	}
 
-	public BytecodeGen(HashMap<String,byte[]> classFiles, List<ResultSet> listOfResultSets,SourceFile sf ,String path) {
+	public BytecodeGen(HashMap<String, byte[]> classFiles, List<ResultSet> listOfResultSets, SourceFile sf,
+			String path) {
 		this.classFiles = classFiles;
 		this.listOfResultSets = listOfResultSets;
 		this.sf = sf;
 		this.path = path;
 	}
-	
+
 	@Override
 	public void visit(SourceFile sourceFile) {
-		for(ClassOrInterface cl : sourceFile.getClasses()) {
+		for (ClassOrInterface cl : sourceFile.getClasses()) {
 			System.out.println("in Class: " + cl.getClassName().toString());
 			BytecodeGen classGen = new BytecodeGen(classFiles, listOfResultSets, sf, path);
 			cl.accept(classGen);
@@ -112,73 +116,74 @@ public class BytecodeGen implements ASTVisitor {
 			classGen.writeClass(cl.getClassName().toString());
 		}
 	}
-	
+
 	/**
-	 * Associates the bytecode of the class that was build with the classWriter {@link #cw}
-	 * with the class name in the map {@link #classFiles}
+	 * Associates the bytecode of the class that was build with the classWriter
+	 * {@link #cw} with the class name in the map {@link #classFiles}
 	 * 
 	 * @param name name of the class with which the the bytecode is to be associated
 	 */
 	private void writeClass(String name) {
 		bytecode = cw.toByteArray();
 		classFiles.put(name, bytecode);
-		
+
 	}
-	
-	public HashMap<String,byte[]> getClassFiles() {
+
+	public HashMap<String, byte[]> getClassFiles() {
 		return classFiles;
 	}
-	
-	
+
 	@Override
 	public void visit(ClassOrInterface classOrInterface) {
-		
-		className = classOrInterface.getClassName().toString();
-		
-		cw.visitSource(className +".jav", null);
-		
-		isInterface = (classOrInterface.getModifiers()&512)==512;
 
-		int acc = isInterface?classOrInterface.getModifiers()+Opcodes.ACC_ABSTRACT:classOrInterface.getModifiers()+Opcodes.ACC_SUPER;
-		
+		className = classOrInterface.getClassName().toString();
+
+		cw.visitSource(className + ".jav", null);
+
+		isInterface = (classOrInterface.getModifiers() & 512) == 512;
+
+		int acc = isInterface ? classOrInterface.getModifiers() + Opcodes.ACC_ABSTRACT
+				: classOrInterface.getModifiers() + Opcodes.ACC_SUPER;
+
 		fieldInitializations = classOrInterface.getfieldInitializations();
-		
+
 //		resultSet = listOfResultSets.get(0);
 		boolean isConsWithNoParamsVisited = false;
 		boolean isVisited = false;
-		for(ResultSet rs : listOfResultSets) {
+		for (ResultSet rs : listOfResultSets) {
 			superClass = classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor());
 			resultSet = rs;
 			tphExtractor.setResultSet(resultSet);
-			
+
 			// Nur einmal ausführen!!
-			if(!isVisited) {
+			if (!isVisited) {
 				classOrInterface.accept(tphExtractor);
 
 				getCommonTPHS(tphExtractor);
-				
+
 				tphsClass = new ArrayList<>();
-				for(String t : tphExtractor.allTPHS.keySet()) {
-					if(!tphExtractor.allTPHS.get(t))
+				for (String t : tphExtractor.allTPHS.keySet()) {
+					if (!tphExtractor.allTPHS.get(t))
 						tphsClass.add(t);
 				}
 
 				String sig = null;
-				/* if class has generics then creates signature
-				 * Signature looks like:
-				 * <E:Ljava/...>Superclass 
+				/*
+				 * if class has generics then creates signature Signature looks like:
+				 * <E:Ljava/...>Superclass
 				 */
-				if(classOrInterface.getGenerics().iterator().hasNext() || !commonPairs.isEmpty() || 
-						classOrInterface.getSuperClass().acceptTV(new TypeToSignature()).contains("<")
+				if (classOrInterface.getGenerics().iterator().hasNext() || !commonPairs.isEmpty()
+						|| classOrInterface.getSuperClass().acceptTV(new TypeToSignature()).contains("<")
 						|| !tphsClass.isEmpty()) {
-					HashMap<TPHConstraint, HashSet<String>> constraints = Simplify.simplifyConstraintsClass(tphExtractor,tphsClass);
+					HashMap<TPHConstraint, HashSet<String>> constraints = Simplify
+							.simplifyConstraintsClass(tphExtractor, tphsClass);
 					ArrayList<TPHConstraint> consClass = new ArrayList<>();
-					for(TPHConstraint cons : constraints.keySet()) {
+					for (TPHConstraint cons : constraints.keySet()) {
 						String right = null;
 						boolean isToAdd = false;
-						for(String tph : tphsClass) {
-							if(cons.getLeft().equals(tph)) {
-								
+						for (String tph : tphsClass) {
+							if (cons.getLeft().equals(tph)) {
+
 								consClass.add(cons);
 								try {
 									right = getTPH(cons.getRight());
@@ -186,14 +191,14 @@ public class BytecodeGen implements ASTVisitor {
 								} catch (NoSuchElementException e) {
 									continue;
 								}
-								
+
 							}
 						}
-						if(isToAdd) {
+						if (isToAdd) {
 							tphsClass.add(right);
 							removeFromMethod(right);
 							right = null;
-							isToAdd= false;
+							isToAdd = false;
 						}
 //						if(right != null) {
 //							tphsClass.add(right);
@@ -201,73 +206,74 @@ public class BytecodeGen implements ASTVisitor {
 //							right = null;
 //						}
 					}
-					
+
 					SimplifyResult sRes = new SimplifyResult(consClass, tphsClass, new HashMap<>());
 					simplifyResults.put(className, sRes);
-					
-					Signature signature = new Signature(classOrInterface, genericsAndBounds,commonPairs,tphsClass, consClass);
+
+					Signature signature = new Signature(classOrInterface, genericsAndBounds, commonPairs, tphsClass,
+							consClass);
 					sig = signature.toString();
 					System.out.println("Signature: => " + sig);
 				}
-				
-				cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString()
-						, sig, classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()), null);
-				
+
+				cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString(), sig,
+						classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()), null);
+
 				isVisited = true;
 			}
-			
-			for(Field f : classOrInterface.getFieldDecl()) {
+
+			for (Field f : classOrInterface.getFieldDecl()) {
 				f.accept(this);
 			}
-			
-			for(Constructor c : classOrInterface.getConstructors()) {
+
+			for (Constructor c : classOrInterface.getConstructors()) {
 //				if(!isConsWithNoParamsVisited) {
-					c.accept(this);
+				c.accept(this);
 //				}
-					
+
 //				if(!c.getParameterList().iterator().hasNext())
 //					isConsWithNoParamsVisited = true;
 			}
-			
-			for(Method m : classOrInterface.getMethods()) {
+
+			for (Method m : classOrInterface.getMethods()) {
 				m.accept(this);
 			}
-		
+
 		}
-		
+
 	}
 
 	private void removeFromMethod(String name) {
-		for(MethodAndTPH m : tphExtractor.ListOfMethodsAndTph) {
+		for (MethodAndTPH m : tphExtractor.ListOfMethodsAndTph) {
 			ArrayList<String> toRemove = new ArrayList<>();
-			for(String tph : m.getTphs()) {
-				if(tph.equals(name)) {
+			for (String tph : m.getTphs()) {
+				if (tph.equals(name)) {
 					toRemove.add(tph);
 				}
 			}
-			
-			if(!toRemove.isEmpty()) {
+
+			if (!toRemove.isEmpty()) {
 				m.getTphs().removeAll(toRemove);
 				return;
 			}
 		}
-		
+
 	}
 
 	private String getTPH(String name) {
-		for(String tph: tphExtractor.allTPHS.keySet()) {
-			if(tph.equals(name))
+		for (String tph : tphExtractor.allTPHS.keySet()) {
+			if (tph.equals(name))
 				return tph;
 		}
-		throw new NoSuchElementException("TPH "+name +" does not exist");
+		throw new NoSuchElementException("TPH " + name + " does not exist");
 	}
 
 	private void getCommonTPHS(TPHExtractor tphExtractor) {
 		// Gemeinsame TPHs
 		ArrayList<String> cTPHs = new ArrayList<>();
 		// Alle TPHs der Felder speichern
-		for(String tph : tphExtractor.allTPHS.keySet()) {
-			if(!tphExtractor.allTPHS.get(tph))
+		for (String tph : tphExtractor.allTPHS.keySet()) {
+			if (!tphExtractor.allTPHS.get(tph))
 				cTPHs.add(tph);
 		}
 	}
@@ -275,157 +281,168 @@ public class BytecodeGen implements ASTVisitor {
 	@Override
 	public void visit(Constructor field) {
 		System.out.println("ResultSet: ");
-		resultSet.results.forEach(a->{
+		resultSet.results.forEach(a -> {
 			System.out.println(a.getLeft().toString() + " = " + a.getRight().toString());
 		});
 		System.out.println("---------------");
-		
+
 		// stores generics and their bounds of method
 		HashMap<String, String> genericsAndBoundsMethod = new HashMap<>();
-		
+
 		field.getParameterList().accept(this);
-		
-		String methParamTypes = field.name+"%%";
-		
+
+		String methParamTypes = field.name + "%%";
+
 		Iterator<FormalParameter> itr = field.getParameterList().iterator();
-		while(itr.hasNext()) {
+		while (itr.hasNext()) {
 			FormalParameter fp = itr.next();
-			methParamTypes += resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+";";
+			methParamTypes += resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()) + ";";
 //			methParamTypes += resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToSignature())+";";
 		}
-		
-		if(methodNameAndParamsT.contains(methParamTypes)) {
-			System.out.println("ignore - Method: "+field.name +" , paramsType: "+methParamTypes);
+
+		if (methodNameAndParamsT.contains(methParamTypes)) {
+			System.out.println("ignore - Method: " + field.name + " , paramsType: " + methParamTypes);
 			return;
 		}
 		methodNameAndParamsT.add(methParamTypes);
-		System.out.println("Method: "+field.name +" , paramsType: "+methParamTypes);
-		
+		System.out.println("Method: " + field.name + " , paramsType: " + methParamTypes);
+
 		String desc = null;
 		boolean hasGen = false;
-		
-		for(String paramName : methodParamsAndTypes.keySet()) {
+
+		for (String paramName : methodParamsAndTypes.keySet()) {
 			String typeOfParam = methodParamsAndTypes.get(paramName).acceptTV(new TypeToSignature());
 			System.out.println(typeOfParam);
-			if(genericsAndBounds.containsKey(typeOfParam) ||typeOfParam.contains("$")
-					|| typeOfParam.contains("<")) {
+			if (genericsAndBounds.containsKey(typeOfParam) || typeOfParam.contains("$") || typeOfParam.contains("<")) {
 				hasGen = true;
 				break;
 			}
 		}
 		String sig = null;
-		if(hasGen) {
-			HashMap<TPHConstraint, HashSet<String>> constraints = Simplify.simplifyConstraints(field.name, tphExtractor,tphsClass);
-			Signature signature = new Signature(field, genericsAndBounds,methodParamsAndTypes,resultSet,constraints);
+		if (hasGen) {
+			HashMap<TPHConstraint, HashSet<String>> constraints = Simplify.simplifyConstraints(field.name, tphExtractor,
+					tphsClass);
+			Signature signature = new Signature(field, genericsAndBounds, methodParamsAndTypes, resultSet, constraints);
 			sig = signature.toString();
 		}
-		if(field.getParameterList().iterator().hasNext())
+		if (field.getParameterList().iterator().hasNext())
 			System.out.println(field.getParameterList().iterator().next().getType().acceptTV(new TypeToDescriptor()));
-		
-		NormalConstructor constructor = new NormalConstructor(field,genericsAndBounds,hasGen);
+
+		NormalConstructor constructor = new NormalConstructor(field, genericsAndBounds, hasGen);
 		desc = constructor.accept(new DescriptorToString(resultSet));
-		System.out.println("Constructor: " + field.getName() + " Sig: "+ sig + " Desc: " + desc);
+		System.out.println("Constructor: " + field.getName() + " Sig: " + sig + " Desc: " + desc);
 		MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", desc, sig, null);
-		mv.visitCode();	
-		
+		mv.visitCode();
+
 		Block block = fieldInitializations.get().block;
-		
+
 		constructorPos += 1;
-		
-		BytecodeGenMethod gen = new BytecodeGenMethod(className,superClass,resultSet,field, mv,paramsAndLocals,cw,
-				genericsAndBoundsMethod,genericsAndBounds,isInterface,classFiles, sf,path, block, constructorPos);
-		if(!field.getParameterList().iterator().hasNext() && !(field.block.statements.get(field.block.statements.size()-1) instanceof ReturnVoid)) {
+
+		BytecodeGenMethod gen = new BytecodeGenMethod(className, superClass, resultSet, field, mv, paramsAndLocals, cw,
+				genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path, block, constructorPos);
+		if (!field.getParameterList().iterator().hasNext()
+				&& !(field.block.statements.get(field.block.statements.size() - 1) instanceof ReturnVoid)) {
 			mv.visitInsn(Opcodes.RETURN);
 		}
 		mv.visitMaxs(0, 0);
 		mv.visitEnd();
 	}
-	
+
 	@Override
 	public void visit(Method method) {
-		// TODO: check if the method is static => if static then the first param will be stored in pos 0
+		// TODO: check if the method is static => if static then the first param will be
+		// stored in pos 0
 		// else it will be stored in pos 1 and this will be stored in pos 0
 		String retType = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor());
 //		String retType = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature());
-		String methParamTypes = retType+method.name+"%%";
+		String methParamTypes = retType + method.name + "%%";
 		method.getParameterList().accept(this);
 
 		Iterator<FormalParameter> itr = method.getParameterList().iterator();
-		while(itr.hasNext()) {
+		while (itr.hasNext()) {
 			FormalParameter fp = itr.next();
-			methParamTypes += resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+";";
+			methParamTypes += resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()) + ";";
 //			methParamTypes += resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToSignature())+";";
 		}
-		
-		if(methodNameAndParamsT.contains(methParamTypes)) {
+
+		if (methodNameAndParamsT.contains(methParamTypes)) {
 			return;
 		}
 		methodNameAndParamsT.add(methParamTypes);
-		System.out.println("Method: "+method.name +" , paramsType: "+methParamTypes);
+		System.out.println("Method: " + method.name + " , paramsType: " + methParamTypes);
 		// stores generics and their bounds of method
 		HashMap<String, String> genericsAndBoundsMethod = new HashMap<>();
 		String methDesc = null;
-		
+
 		// Method getModifiers() ?
-		int acc = isInterface?Opcodes.ACC_ABSTRACT:method.modifier;
+		int acc = isInterface ? Opcodes.ACC_ABSTRACT : method.modifier;
 		System.out.println(acc);
-		
-		/*Prüfe, ob die Rückgabe-Type der Methode eine Type-Variable ist*/
-		boolean hasGenInParameterList = genericsAndBounds.containsKey(retType) || retType.contains("TPH ") ||
-										resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature()).contains("<");
-		/*Wenn die Rückgabe-Type eine Typ-variable ist, erzeuge direkt die Signature, wenn nicht,
-		 * prüfe, ob einer der Parameter Typ-Variable als Typ hat*/
-		if(!hasGenInParameterList) {
-			for(String paramName : methodParamsAndTypes.keySet()) {
+
+		/* Prüfe, ob die Rückgabe-Type der Methode eine Type-Variable ist */
+		boolean hasGenInParameterList = genericsAndBounds.containsKey(retType) || retType.contains("TPH ")
+				|| resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature())
+						.contains("<");
+		/*
+		 * Wenn die Rückgabe-Type eine Typ-variable ist, erzeuge direkt die Signature,
+		 * wenn nicht, prüfe, ob einer der Parameter Typ-Variable als Typ hat
+		 */
+		if (!hasGenInParameterList) {
+			for (String paramName : methodParamsAndTypes.keySet()) {
 				String typeOfParam = methodParamsAndTypes.get(paramName).acceptTV(new TypeToDescriptor());
 				String sigOfParam = methodParamsAndTypes.get(paramName).acceptTV(new TypeToSignature());
-				if(genericsAndBounds.containsKey(typeOfParam)||typeOfParam.contains("TPH ")||sigOfParam.contains("<")) {
+				if (genericsAndBounds.containsKey(typeOfParam) || typeOfParam.contains("TPH ")
+						|| sigOfParam.contains("<")) {
 					hasGenInParameterList = true;
 					break;
 				}
 			}
 		}
-		//TODO: Test if the return-type or any of the parameter is a parameterized type. (VP)
-		//then create the descriptor with the new syntax.
-		
+		// TODO: Test if the return-type or any of the parameter is a parameterized
+		// type. (VP)
+		// then create the descriptor with the new syntax.
+
 		String sig = null;
-		/* method.getGenerics: <....> RT method(..) 
-		 * */
+		/*
+		 * method.getGenerics: <....> RT method(..)
+		 */
 		boolean hasGen = method.getGenerics().iterator().hasNext() || hasGenInParameterList;
 		/* if method has generics or return type is TPH, create signature */
 		// zwite operand muss weggelassen werden
-		if(hasGen||resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToString()).equals("TPH")) {
+		if (hasGen || resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToString())
+				.equals("TPH")) {
 			System.out.println("ALL CONST: " + tphExtractor.allCons.size());
-			tphExtractor.allCons.forEach(c->System.out.println(c.toString()));
+			tphExtractor.allCons.forEach(c -> System.out.println(c.toString()));
 			System.out.println("----------------");
-			HashMap<TPHConstraint, HashSet<String>> constraints = Simplify.simplifyConstraints(method.name, tphExtractor, tphsClass);
+			HashMap<TPHConstraint, HashSet<String>> constraints = Simplify.simplifyConstraints(method.name,
+					tphExtractor, tphsClass);
 //			ArrayList<GenericInsertPair> pairs = simplifyPairs(method.name,tphExtractor.allPairs,tphExtractor.allCons);
-			Signature signature = new Signature(method, genericsAndBoundsMethod, genericsAndBounds,methodParamsAndTypes,resultSet,constraints);
+			Signature signature = new Signature(method, genericsAndBoundsMethod, genericsAndBounds,
+					methodParamsAndTypes, resultSet, constraints);
 			sig = signature.toString();
-			if(simplifyResults.containsKey(className)) {
+			if (simplifyResults.containsKey(className)) {
 				simplifyResults.get(className).getMethodsConstraints().put(methParamTypes, constraints);
 			} else {
 				SimplifyResult sRes = new SimplifyResult(new ArrayList<>(), new ArrayList<>(), new HashMap<>());
 				sRes.getMethodsConstraints().put(methParamTypes, constraints);
 				simplifyResults.put(className, sRes);
 			}
-			
-		}
-		System.out.println(method.getName()+" ==> "+sig);
-		NormalMethod meth = new NormalMethod(method,genericsAndBounds,genericsAndBoundsMethod,hasGen);
-		methDesc = meth.accept(new DescriptorToString(resultSet));
-		
-//		System.out.println(methDesc);
-		MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+acc, method.getName(), methDesc, sig, null);
 
-		mv.visitCode();		
-		BytecodeGenMethod gen = new BytecodeGenMethod(className,superClass,resultSet,method, mv,paramsAndLocals,cw,
-				genericsAndBoundsMethod,genericsAndBounds,isInterface,classFiles, sf,path);
-		
+		}
+		System.out.println(method.getName() + " ==> " + sig);
+		NormalMethod meth = new NormalMethod(method, genericsAndBounds, genericsAndBoundsMethod, hasGen);
+		methDesc = meth.accept(new DescriptorToString(resultSet));
+
+//		System.out.println(methDesc);
+		MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + acc, method.getName(), methDesc, sig, null);
+
+		mv.visitCode();
+		BytecodeGenMethod gen = new BytecodeGenMethod(className, superClass, resultSet, method, mv, paramsAndLocals, cw,
+				genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path);
+
 		mv.visitMaxs(0, 0);
 		mv.visitEnd();
 	}
-	
+
 	public HashMap<String, SimplifyResult> getSimplifyResults() {
 		return simplifyResults;
 	}
@@ -436,7 +453,7 @@ public class BytecodeGen implements ASTVisitor {
 		methodParamsAndTypes = new HashMap<>();
 		Iterator<FormalParameter> itr = formalParameters.iterator();
 		int i = 1;
-		while(itr.hasNext()) {
+		while (itr.hasNext()) {
 			FormalParameter fp = itr.next();
 			paramsAndLocals.put(fp.getName(), i);
 			methodParamsAndTypes.put(fp.getName(), resultSet.resolveType(fp.getType()).resolvedType);
@@ -444,39 +461,39 @@ public class BytecodeGen implements ASTVisitor {
 			i++;
 		}
 	}
-	
+
 	@Override
 	public void visit(FormalParameter formalParameter) {
 		formalParameter.getType().accept(this);
 	}
-	
+
 	@Override
 	public void visit(RefType refType) {
-		type = "L"+refType.toString()+";";
+		type = "L" + refType.toString() + ";";
 	}
 
 	@Override
 	public void visit(SuperWildcardType superWildcardType) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(TypePlaceholder typePlaceholder) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(ExtendsWildcardType extendsWildcardType) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(GenericRefType genericRefType) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	// ??
@@ -484,48 +501,51 @@ public class BytecodeGen implements ASTVisitor {
 	public void visit(FieldVar fieldVar) {
 		System.out.println("In FieldVar ---");
 //		cw.newField(fieldVar.receiver.toString(), fieldVar.fieldVarName.toString(), fieldVar.getType().toString());
-		FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, fieldVar.fieldVarName, "L"+fieldVar.getType()+";", null, null);
+		FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, fieldVar.fieldVarName, "L" + fieldVar.getType() + ";",
+				null, null);
 		fv.visitEnd();
 	}
-	
+
 	@Override
 	public void visit(Field field) {
 		System.out.println("In Field ---");
 		String des = "L";
-		if(resultSet.resolveType(field.getType()).resolvedType instanceof TypePlaceholder) {
+		if (resultSet.resolveType(field.getType()).resolvedType instanceof TypePlaceholder) {
 			des += Type.getInternalName(Object.class);
 		} else {
 			des += resultSet.resolveType(field.getType()).resolvedType.acceptTV(new TypeToDescriptor());
 		}
-		des +=";";
+		des += ";";
 		System.out.println(des);
 		String sig = resultSet.resolveType(field.getType()).resolvedType.acceptTV(new TypeToSignature());
 		System.out.println(sig);
-		if(sig.charAt(sig.length()-1) != (";").charAt(0)) {
-			sig +=";";
-		}	
+		if (sig.charAt(sig.length() - 1) != (";").charAt(0)) {
+			sig += ";";
+		}
 		String nameAndDesc = field.getName() + "%%" + des;
-		
-		if(fieldNameAndParamsT.contains(nameAndDesc))
+		String nameAndSig = field.getName() + "%%" + sig;
+		if (fieldNameAndParamsT.contains(nameAndDesc)) {
+			if (fieldNameSignature.contains(nameAndSig)) {
+				return;
+			}
 			throw new BytecodeGeneratorError("Bytecode generation aborted due to duplicate field name&signature");
-		
+		}
 		fieldNameAndParamsT.add(nameAndDesc);
-		
-		cw.visitField(field.modifier, field.getName(),
-				des, sig, 
-				null);
+		fieldNameSignature.add(nameAndSig);
+
+		cw.visitField(field.modifier, field.getName(), des, sig, null);
 	}
 
 	@Override
 	public void visit(LambdaExpression lambdaExpression) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(Assign assign) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
@@ -536,151 +556,151 @@ public class BytecodeGen implements ASTVisitor {
 	@Override
 	public void visit(Block block) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(CastExpr castExpr) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(EmptyStmt emptyStmt) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(ForStmt forStmt) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(IfStmt ifStmt) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(InstanceOf instanceOf) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(LocalVar localVar) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(LocalVarDecl localVarDecl) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(MethodCall methodCall) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(NewClass methodCall) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(NewArray newArray) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(Return aReturn) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(ReturnVoid aReturn) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(StaticClassName staticClassName) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(Super aSuper) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(This aThis) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(WhileStmt whileStmt) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(DoStmt whileStmt) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	// ???
 	@Override
 	public void visit(Literal literal) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(ArgumentList argumentList) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(GenericTypeVar genericTypeVar) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(GenericDeclarationList genericTypeVars) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(AssignToField assignLeftSide) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(AssignToLocal assignLeftSide) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void visit(SuperCall superCall) {
-		
+
 	}
 
 	@Override
@@ -693,6 +713,5 @@ public class BytecodeGen implements ASTVisitor {
 	public void visit(UnaryExpr unaryExpr) {
 		throw new NotImplementedException();
 	}
-	
 
 }
diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java
index f047e251..abf7237a 100644
--- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java
+++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java
@@ -678,7 +678,7 @@ public class BytecodeGenMethod implements StatementVisitor {
 		}
 		methSig.visitReturnType().visitTypeVariable("R");
 		// ")"+lam.getReturn.getBounds
-		Signature sig = new Signature(lambdaExpression, numberOfParams);
+		Signature sig = new Signature(numberOfParams);
 		String name = "Fun" + numberOfParams + "$$";
 		classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(),
 				Type.getInternalName(Object.class), null);
@@ -778,9 +778,9 @@ public class BytecodeGenMethod implements StatementVisitor {
 		
 		String mDesc = "";
 		
-		MethodCallHelper helper = new MethodCallHelper(methodCall, sf, resultSet);
+		MethodCallHelper helper = new MethodCallHelper(methodCall, sf, resultSet, path);
 		
-		boolean isCreated = false;
+		boolean toCreate = false;
 
 		ClassLoader cLoader = ClassLoader.getSystemClassLoader();
 		// This will be used if the class is not standard class (not in API)
@@ -799,7 +799,6 @@ public class BytecodeGenMethod implements StatementVisitor {
 
 			} catch (Exception e) {
 					String superClass = "";
-					// TODO: Test SubMatrix.jav
 					while(true) {
 						try {
 							superClass = helper.getSuperClass(receiverName);
@@ -833,25 +832,29 @@ public class BytecodeGenMethod implements StatementVisitor {
 			}
 			
 			if(methodRefl == null) {
-				isCreated = !receiverName.equals(className) && helper.isInCurrPkg(clazz);
-				if(isCreated) {
+				toCreate = !receiverName.equals(className) && helper.isInCurrPkg(clazz);
+				if(toCreate) {
 					try {
 						mDesc = helper.getDesc(clazz);
 					} catch (NotInCurrentPackageException | NotFoundException e) {
 						e.printStackTrace();
 					}
 				} else if(!helper.isInCurrPkg(clazz)){
-					try {
-						cLoader2 = new URLClassLoader(new URL[] {new URL("file://"+path)});
-						java.lang.reflect.Method[] methods = cLoader2.loadClass(clazz).getMethods();
-						System.out.println("Methods of " + receiverName + " ");
-						for(int i = 0; i<methods.length; i++) {
-							System.out.println(methods[i]);
+					if(clazz.contains("$$")) {
+						mDesc = helper.generateBCForFunN();
+					}else {
+						try {
+							cLoader2 = new URLClassLoader(new URL[] {new URL("file://"+path)});
+							java.lang.reflect.Method[] methods = cLoader2.loadClass(clazz).getMethods();
+							System.out.println("Methods of " + receiverName + " ");
+							for(int i = 0; i<methods.length; i++) {
+								System.out.println(methods[i]);
+							}
+							methodRefl = getMethod(methodCall.name,methodCall.arglist.getArguments().size(),methCallType, typesOfParams,methods);
+						}
+						catch (Exception e2) {
+							e2.printStackTrace();
 						}
-						methodRefl = getMethod(methodCall.name,methodCall.arglist.getArguments().size(),methCallType, typesOfParams,methods);
-					}
-					catch (Exception e2) {
-						e2.printStackTrace();
 					}
 				}
 				
diff --git a/src/main/java/de/dhbwstuttgart/bytecode/signature/Signature.java b/src/main/java/de/dhbwstuttgart/bytecode/signature/Signature.java
index dd7f5d60..62a55d12 100644
--- a/src/main/java/de/dhbwstuttgart/bytecode/signature/Signature.java
+++ b/src/main/java/de/dhbwstuttgart/bytecode/signature/Signature.java
@@ -80,12 +80,12 @@ public class Signature {
 		createSignatureForConsOrMethod(this.method,false);
 	}
 	
-	public Signature(LambdaExpression lambdaExpression,int numberOfParams) {
+	public Signature(int numberOfParams) {
 		sw = new SignatureWriter();
-		createSignatureForFunN(lambdaExpression, numberOfParams);
+		createSignatureForFunN(numberOfParams);
 	}
 
-	private void createSignatureForFunN(LambdaExpression lambdaExpression, int numberOfParams) {
+	private void createSignatureForFunN(int numberOfParams) {
 		
 //		sw.visitClassBound().visitEnd();
 		for(int i = 0;i<numberOfParams;i++) {
diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodCallHelper.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodCallHelper.java
index 7a48d10b..afeaa6c1 100644
--- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodCallHelper.java
+++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodCallHelper.java
@@ -3,6 +3,10 @@
  */
 package de.dhbwstuttgart.bytecode.utilities;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -11,11 +15,17 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
+import org.objectweb.asm.signature.SignatureVisitor;
+import org.objectweb.asm.signature.SignatureWriter;
 
 import de.dhbwstuttgart.bytecode.Exception.NotInCurrentPackageException;
 import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString;
 import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor;
+import de.dhbwstuttgart.bytecode.signature.Signature;
 import de.dhbwstuttgart.bytecode.signature.TypeToSignature;
 import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
 import de.dhbwstuttgart.syntaxtree.FormalParameter;
@@ -23,6 +33,8 @@ import de.dhbwstuttgart.syntaxtree.GenericDeclarationList;
 import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
 import de.dhbwstuttgart.syntaxtree.Method;
 import de.dhbwstuttgart.syntaxtree.SourceFile;
+import de.dhbwstuttgart.syntaxtree.statement.Expression;
+import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression;
 import de.dhbwstuttgart.syntaxtree.statement.MethodCall;
 import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
 import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
@@ -38,16 +50,19 @@ public class MethodCallHelper {
 	private MethodCall methCall;
 	private SourceFile sourceFile;
 	private ResultSet resultSet;
+	private String path;
 
 	/**
 	 * @param methCall
 	 * @param sourceFile
 	 * @param resultSet
+	 * @param path TODO
 	 */
-	public MethodCallHelper(MethodCall methCall, SourceFile sourceFile, ResultSet resultSet) {
+	public MethodCallHelper(MethodCall methCall, SourceFile sourceFile, ResultSet resultSet, String path) {
 		this.methCall = methCall;
 		this.sourceFile = sourceFile;
 		this.resultSet = resultSet;
+		this.path = path;
 	}
 
 	public String getResolvedType(RefTypeOrTPHOrWildcardOrGeneric type) {
@@ -189,19 +204,52 @@ public class MethodCallHelper {
 		}
 	}
 
-	private String createDesc(Method m) {
-		String desc = "(";
-		for (FormalParameter fp : m.getParameterList()) {
-			String typeName = getResolvedType(fp.getType());
-			RefTypeOrTPHOrWildcardOrGeneric type = resultSet.resolveType(fp.getType()).resolvedType;
-			if (type instanceof TypePlaceholder) {
-				desc += "L" + Type.getInternalName(Object.class) + ";";
-			} else if (type instanceof GenericRefType) {
-				GenericRefType grt = (GenericRefType) type;
+	public String generateBCForFunN() {
+		ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
 
-			}
+		SignatureWriter methSig = new SignatureWriter();
+
+		int numberOfParams = 0;
+		SignatureVisitor paramVisitor = methSig.visitParameterType();
+		Iterator<Expression> itr1 = methCall.arglist.getArguments().iterator();
+		String methDesc = "(";
+		while(itr1.hasNext()) {
+			numberOfParams++;
+			// getBounds
+			paramVisitor.visitTypeVariable("T" + numberOfParams);
+			methDesc += "L" + Type.getInternalName(Object.class) + ";";
+			itr1.next();
 		}
-		return null;
+		methDesc += ")L" + Type.getInternalName(Object.class) + ";";
+		
+		methSig.visitReturnType().visitTypeVariable("R");
+		// ")"+lam.getReturn.getBounds
+		Signature sig = new Signature(numberOfParams);
+		String name = "Fun" + numberOfParams + "$$";
+		classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(),
+				Type.getInternalName(Object.class), null);
+		MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc,
+				methSig.toString(), null);
+		mvApply.visitEnd();
+		writeClassFile(classWriter.toByteArray(), name);
+		return methDesc;
+	}
+
+	private void writeClassFile(byte[] bytecode, String name) {
+		FileOutputStream output;
+		try {
+			System.out.println("generating " + name + ".class file...");
+			output = new FileOutputStream(
+					new File(path + name + ".class"));
+			output.write(bytecode);
+			output.close();
+			System.out.println(name + ".class file generated");
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+
 	}
 
 }
diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodFromMethodCall.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodFromMethodCall.java
index 2028c772..28d135e6 100644
--- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodFromMethodCall.java
+++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodFromMethodCall.java
@@ -23,6 +23,7 @@ public class MethodFromMethodCall {
 		this.genericsAndBounds = genericsAndBounds;
 	}
 	
+	
 	public ArgumentList getArgList() {
 		return argList;
 	}