package de.dhbwstuttgart.syntaxtree; import org.apache.bcel.generic.ClassGen; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.InstructionFactory; import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InstructionList; import org.apache.bcel.generic.MethodGen; import de.dhbwstuttgart.logger.Logger; import de.dhbwstuttgart.logger.Section; import de.dhbwstuttgart.logger.SectionLogger; import de.dhbwstuttgart.bytecode.ClassGenerator; import de.dhbwstuttgart.bytecode.DHBWConstantPoolGen; import de.dhbwstuttgart.bytecode.DHBWInstructionFactory; import de.dhbwstuttgart.core.IItemWithOffset; import de.dhbwstuttgart.parser.JavaClassName; import de.dhbwstuttgart.syntaxtree.modifier.Modifiers; import de.dhbwstuttgart.syntaxtree.modifier.Static; import de.dhbwstuttgart.syntaxtree.statement.Block; import de.dhbwstuttgart.syntaxtree.statement.Expr; import de.dhbwstuttgart.syntaxtree.statement.Statement; import de.dhbwstuttgart.syntaxtree.statement.SuperCall; import de.dhbwstuttgart.syntaxtree.type.GenericTypeVar; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.Type; import de.dhbwstuttgart.typeinference.*; import de.dhbwstuttgart.typeinference.assumptions.ClassAssumption; import de.dhbwstuttgart.typeinference.assumptions.TypeAssumptions; import java.util.ArrayList; import java.util.List; /** * Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces */ public class Class extends GTVDeclarationContext implements IItemWithOffset, Generic, GenericTypeInsertable { /** * Loggerinstanzen */ protected static Logger inferencelog = Logger.getLogger("inference"); protected static Logger codegenlog = Logger.getLogger("codegen"); protected static Logger parserlog = Logger.getLogger("parser"); protected Logger typinferenzLog = Logger.getLogger(Class.class.getName()); protected Modifiers modifiers; protected JavaClassName name; private Block class_block; private List fielddecl = new ArrayList<>(); private GenericDeclarationList genericClassParameters; private int offset; private RefType superClass; protected boolean isInterface; private List implementedInterfaces; ///////////////////////////////////////////////////////////////////////// // TypeReconstructionAlgorithmus ///////////////////////////////////////////////////////////////////////// /** * Ausgangspunkt f�r den Typrekonstruktionsalgorithmus. Hier werden zun�chst * die Mengen von Typannahmen V_fields_methods und V_i erstellt, die als Eingabe * f�r den Algorithmus dienen.
* (siehe Algorithmus 5.17 TRProg, Martin Pl�micke) *
Author: J�rg B�uerle * @param supportData * @param globalAssumptions * @return Liste aller bisher berechneten, m�glichen Typkombinationen * @throws CTypeReconstructionException */ public ConstraintsSet typeReconstruction(TypeAssumptions globalAssumptions) { ////////////////////////////// // Und los geht's: ////////////////////////////// inferencelog.info("Rufe TRStart()...", Section.TYPEINFERENCE); ////////////////////////////// // Ab hier ... // @author A10023 - Andreas Stadelmeier: ////////////////////////////// //Erzeuge Assumptions: TypeAssumptions assumptions = this.getPrivateFieldAssumptions(); //Globale Assumptions anfügen: assumptions.add(globalAssumptions); ConstraintsSet oderConstraints = new ConstraintsSet(); for(Type gparam : this.get_ParaList()){ if(gparam instanceof GenericTypeVar)assumptions.add(((GenericTypeVar)gparam).createAssumptions()); //Constraints für die Generischen Variablen erstellen und diese dem AssumptionsSet hinzufügen } for(Type gparam : this.get_ParaList()){ if(gparam instanceof GenericTypeVar)oderConstraints.add(((GenericTypeVar)gparam).TYPE(assumptions)); //Constraints für die Generischen Variablen erstellen und diese dem AssumptionsSet hinzufügen } typinferenzLog.debug("Erstellte Assumptions: "+assumptions, Section.TYPEINFERENCE); //Gibt es hier eine ClassCastException stimmt etwas grundsätzlich nicht! //this.superClass = (RefType)this.superClass.TYPE(assumptions, this); for(Field f:this.getFields()){ oderConstraints.add(f.TYPE(assumptions)); } typinferenzLog.debug("Erstellte Constraints: "+oderConstraints, Section.TYPEINFERENCE); return oderConstraints; } /** * Ermittelt alle privaten Felder und Methoden der Klasse und Erstellt eine Assumption für diese. * Bemerkung: Momentan werden noch alle Felder dieser Klasse zurückgegeben. * @return Die erstellten TypeAssumptions */ private TypeAssumptions getPrivateFieldAssumptions() { if(this.typeAssumptions != null)return this.typeAssumptions; //Das sorgt dafür, dass die Assumptions nur einmalig generiert werden. TypeAssumptions assumptions = new TypeAssumptions(this.getName()); for(Field field : this.getFields()){ if(!field.isPublic())assumptions.add(field.createTypeAssumptions(this)); } this.typeAssumptions = assumptions; //Diese müssen anschließend nicht wieder generiert werden. return assumptions; } /** *
Author: Martin Pl�micke * @return */ public String toString() { return name.toString(); } public String getTypeInformation(Menge methodList, Menge fieldList){ String ret = this.name+": "; for(Expr field : fieldList){ ret+=field.getTypeInformation()+"\n"; } for(Method m : methodList){ ret+=m.getTypeInformation()+"\n"; } return ret; } /** * Generiert den JavaCode dieser Klasse im Falle für das übergebene resultSet. * Dem ResultSet entsprechend werden in diesem Java-Code die TypePlaceholder durch die in ResultSet stehenden Typen ersetzt. * @return Java-Sourcefile */ public JavaCodeResult printJavaCode(ResultSet reconstructionResult){ JavaCodeResult ret = new JavaCodeResult("class "); JavaCodeResult classBodyCode = new JavaCodeResult(); if(this.modifiers!=null)classBodyCode.attach(this.modifiers.printJavaCode(reconstructionResult)).attach(" "); classBodyCode.attach(this.name + " extends ").attach(this.superClass.printJavaCode(reconstructionResult)).attach("\n"); JavaCodeResult bodyString = new JavaCodeResult("{\n"); for(Field field : this.fielddecl)bodyString.attach( field.printJavaCode(reconstructionResult) ).attach( "\n" ); bodyString.attach("}\n"); classBodyCode.attach(bodyString); //Zuerst die generischen Parameter für diese Klasse berechnen: //this.createGenericTypeVars(classBodyCode.getUnresolvedTPH()); if(this.genericClassParameters != null && this.genericClassParameters.size()>0){ ret.attach("<"); Iterator it = this.genericClassParameters.iterator(); while(it.hasNext()){ GenericTypeVar tph = it.next(); ret.attach(tph.printJavaCode(reconstructionResult)); if(it.hasNext())ret.attach(", "); } ret.attach(">"); } String stringReturn = ret.attach(classBodyCode).toString(); return new JavaCodeResult(stringReturn); } public int getOffset(){ return this.offset; } /** * Erstellt einen RefType, welcher auf diese Klasse verweist * Ersetzt alle Generischen Variablen in der Parameterliste mit TPH * @return */ public RefType getType() { return new RefType(this.getName().toString(), this.get_ParaList(),this, 0); } /** * Ermittelt die Sichtbaren Felder und Methoden der Klasse. * (Momentan sind im Projekt alle Felder und Methoden "package private", da der Parser keine Access-Modifier einlesen kann. * @return */ public TypeAssumptions getPublicFieldAssumptions() { TypeAssumptions ret = new TypeAssumptions();//this.getPrivateFieldAssumptions(); ret.addClassAssumption(new ClassAssumption(this)); for(Field f : this.getFields()){ if(f.isPublic())ret.add(f.createTypeAssumptions(this)); } for(GenericTypeVar gtv : this.getGenericParameter()){ ret.add(gtv.createAssumptions()); } return ret; } @Override public boolean equals(Object obj){ if(!(obj instanceof Class))return false; Class cl = (Class) obj; if(!(cl.getName().equals(this.getName())))return false; return true; } @Override public GenericDeclarationList getGenericParameter() { return this.genericClassParameters; } @Override public String getDescription(){ return "class "+this.getName(); } @Override public void setGenericParameter(GenericDeclarationList params) { this.genericClassParameters = params; } @Override public String getGenericVarDeclarationString(String genericVarDeclaration) { if(this.genericClassParameters != null){ return ", "+genericVarDeclaration; }else{ return "<"+genericVarDeclaration+">"; } } @Override public int getGenericVarDeclarationOffset(){ // Falls Generische Parameterliste vorhanden, hier Wert der Liste zurückgegebn if(this.genericClassParameters != null){ return this.genericClassParameters.getEndOffset(); }else{ return this.offset; } } /** * Die Super Klasse dieser Klasse. * @return null für Klasse Object */ public RefType getSuperClass(){ return this.superClass; } @Override public boolean isClass() { return true; } public boolean isInterface(){ return isInterface; } }