Enrico Schrödter b4d7ab02eb - UnitTest für MultiExtends Problem
- Verhindern von doppelten Methoden von Class -> ClassGen
2016-03-28 10:33:04 +02:00

189 lines
6.4 KiB
Java

package de.dhbwstuttgart.bytecode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.commons.bcel6.classfile.BootstrapMethod;
import org.apache.commons.bcel6.classfile.BootstrapMethods;
import org.apache.commons.bcel6.classfile.ConstantPool;
import org.apache.commons.bcel6.classfile.InnerClass;
import org.apache.commons.bcel6.classfile.InnerClasses;
import org.apache.commons.bcel6.classfile.JavaClass;
import org.apache.commons.bcel6.classfile.Method;
import org.apache.commons.bcel6.classfile.Signature;
import org.apache.commons.bcel6.generic.ClassGen;
import org.apache.commons.bcel6.generic.ConstantPoolGen;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.Type;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.typeinference.Menge;
import de.dhbwstuttgart.typeinference.ResultSet;
import de.dhbwstuttgart.typeinference.TypeinferenceResultSet;
import de.dhbwstuttgart.typeinference.TypeinferenceResults;
import de.dhbwstuttgart.typeinference.exceptions.DebugException;
public class ClassGenerator extends ClassGen{
private DHBWConstantPoolGen cp;
private DHBWInstructionFactory factory;
private TypeinferenceResults tiResult;
private int lambdaMethodeNr = 0;
private Type superClass;
private Menge<TypePlaceholder> usedTPHs = new Menge<>();
private Map<String, ClassGenerator> extraClasses = new HashMap<>();
private List<String> methodsNamesAndTypes = new LinkedList<>();
public ClassGenerator(String name, Type superClass, String string, short accessflags, String[] strings, TypeinferenceResults typeinferenceResults) {
super(name,superClass.get_Name(),string,accessflags,strings, new DHBWConstantPoolGen());
this.tiResult = typeinferenceResults;
this.superClass = superClass;
cp = (DHBWConstantPoolGen) super.getConstantPool();
factory = new DHBWInstructionFactory(this, cp);
this.setMajor(52); //Java 8 Version 52.0
this.setMinor(0);
}
public DHBWInstructionFactory getInstructionFactory() {
return factory ;
}
/**
* Versucht einen Type zu finden von dem dieser TPH ein Subtyp sein muss.
* @param toTPH
* @return Es gilt dann "toTPH extends Type"
*/
public org.apache.commons.bcel6.generic.Type getNearestUsedType(Type t, Menge<TypePlaceholder> usedTypes){
if(t == null){
return this.getInstructionFactory().createObjectType();
}else if(t instanceof TypePlaceholder){ //Es muss sich in diesem Fall um einen TPH handeln:
//return getNearestType((TypePlaceholder) t);
return new TypePlaceholderType((TypePlaceholder) t);
}else{
return t.getBytecodeType(this, getTypeinferenceResults().getTypeReconstructions().firstElement());
}
}
public org.apache.commons.bcel6.generic.Type getNearestUsedType(TypePlaceholder toTPH){
return this.getNearestUsedType(toTPH, null);
}
public String createLambdaMethodName() {
return "lambda$methode$"+(lambdaMethodeNr++);
}
@Override
public DHBWConstantPoolGen getConstantPool(){
return this.cp;
}
@Override
public void setConstantPool(ConstantPoolGen gen){
throw new DebugException("Ungültige Operation. ClassGenerator muss ein DHBWConstantPool besitzen");
}
/**
* Anmerkung: Kann in diesem Zustand nur einmal aufgerufen werden.
* @param innerClassAttribute
*/
public void addInnerClass(InnerClass innerClassAttribute) {
//TODO: Muss vor dem ausführen von getJavaClass ausgeführt werden. getJavaClass überschreiben!
int numberOfInnerClasses = 1;
InnerClass[] innerClasses = new InnerClass[numberOfInnerClasses];
innerClasses[numberOfInnerClasses-1] = innerClassAttribute;
int innerClassesUTF8 = this.getConstantPool().addUtf8("InnerClasses");
this.addAttribute(new InnerClasses(innerClassesUTF8,numberOfInnerClasses*8+2,innerClasses,this.getConstantPool().getConstantPool()));
}
public int addBootstrapMethod(BootstrapMethod bMethod) {
int numberOfBootstrapMethods = 1;
int name_index = this.getConstantPool().addUtf8("BootstrapMethods");
int length = 2 + numberOfBootstrapMethods * 4 + bMethod.getNumBootstrapArguments() * 2;
BootstrapMethod[] bootstrap_methods = new BootstrapMethod[numberOfBootstrapMethods];
bootstrap_methods[numberOfBootstrapMethods-1] = bMethod;
BootstrapMethods bootstrapAttribute = new BootstrapMethods(name_index, length, bootstrap_methods, this.getConstantPool().getConstantPool());
this.addAttribute(bootstrapAttribute);
return numberOfBootstrapMethods-1;
}
public void addUsedTPH(TypePlaceholder tph){
if(! this.getUsedTPH().contains(tph, (a, b)->{
return a.get_Name().equals(b.get_Name()); //Vergleich auf Namensgleichheit. Was anderes zählt im Bytecode nicht
}))
{ //Nur wenn noch nicht vorhanden anfügen:
this.usedTPHs.add(tph);
}
}
public Menge<TypePlaceholder> getUsedTPH() {
return usedTPHs;
}
@Override
public JavaClass getJavaClass() {
//Hier werden die letzten Schritte vor der Klassengenerierung ausgeführt:
//Signatur setzen:
String typeParameters = this.generateParameterSignature();
String superClassSignature = this.superClass.getBytecodeSignature(this, null);
String classSignature = typeParameters + superClassSignature;
if(classSignature.length()>0){
this.addAttribute(new Signature(cp.addUtf8("Signature"),2,cp.addUtf8(classSignature),cp.getConstantPool()));
}
return super.getJavaClass();
}
private String generateParameterSignature(){
String ret = "";
if(this.getUsedTPH().size()>0){
ret += "<";
Iterator<TypePlaceholder> it = ((Menge<TypePlaceholder>)this.getUsedTPH().clone()).iterator();
while(it.hasNext()){
TypePlaceholder tph = it.next();
//ret += tph.getBytecodeMethodSignature(this);
//ret += ":";
ret += tph.getClassSignature(this, getTypeinferenceResults().getTypeReconstructions().firstElement());
}
ret += ">";
}
return ret;
}
public void addExtraClass(ClassGenerator cg){
extraClasses.put(cg.getClassName(), cg);
}
public Map<String, ClassGenerator> getExtraClasses() {
return extraClasses;
}
public TypeinferenceResults getTypeinferenceResults() {
return tiResult;
}
@Override
public void addMethod(Method m) {
String methodNameAndTypes = m.getName()+Arrays.toString(m.getArgumentTypes());
if(methodsNamesAndTypes.contains(methodNameAndTypes)){
return;
}
methodsNamesAndTypes.add(methodNameAndTypes);
super.addMethod(m);
}
}