// ino.module.Class.8553.package package de.dhbwstuttgart.syntaxtree; // ino.end // ino.module.Class.8553.import import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.lang.model.element.Modifier; 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.SuperWildcardType; import de.dhbwstuttgart.syntaxtree.type.Type; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.type.WildcardType; import de.dhbwstuttgart.typeinference.*; import de.dhbwstuttgart.typeinference.assumptions.ClassAssumption; import de.dhbwstuttgart.typeinference.assumptions.TypeAssumptions; import de.dhbwstuttgart.typeinference.exceptions.DebugException; import de.dhbwstuttgart.typeinference.exceptions.NotImplementedException; import de.dhbwstuttgart.typeinference.exceptions.TypeinferenceException; import de.dhbwstuttgart.typeinference.typedeployment.TypeInsertPoint; import de.dhbwstuttgart.typeinference.unify.TypeUnify; import org.apache.bcel.generic.*; import org.apache.bcel.classfile.*; import org.apache.bcel.*; import java.io.*; /** * Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces */ public class Class extends GTVDeclarationContext implements IItemWithOffset, Generic, GenericTypeInsertable // ino.end // ino.class.Class.23010.body { /** * Log4j - 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 Menge superif; public Class(JavaClassName name, List methoden, List felder, Modifiers modifier, boolean isInterface, RefType superClass, List implementedInterfaces, int offset){ } /** * * @param resultSet - Fehlende Typen im Syntaxbaum werden nach diesem ResultSet aufgelöst * @return */ public ByteCodeResult genByteCode(TypeinferenceResults typeinferenceResults) { InstructionFactory _factory; DHBWConstantPoolGen _cp; ClassGenerator _cg; Menge results = new Menge(); SectionLogger logger = Logger.getSectionLogger(this.getClass().getName(), Section.CODEGEN); logger.debug("Test"); short constants = Constants.ACC_PUBLIC; //Per Definition ist jede Methode public _cg = new ClassGenerator(name.toString(), this.getSuperClass(), name.getName() + ".java", constants , new String[] { }, typeinferenceResults); //letzter Parameter sind implementierte Interfaces _cp = _cg.getConstantPool(); _factory = new DHBWInstructionFactory(_cg, _cp); //Die Felder in Methoden Felder und Konstruktoren aufteilen: Menge fieldDeclarations = new Menge<>(); Menge constructors = new Menge<>(); Menge methods = new Menge<>(); for(Field field : this.fielddecl){ if(field instanceof Constructor)constructors.add((Constructor)field); if(field instanceof Method && ! (field instanceof Constructor))methods.add((Method)field); if(field instanceof FieldDeclaration)fieldDeclarations.add((FieldDeclaration)field); //field.genByteCode(_cg); } //Zuerst die Methoden und Felder abarbeiten: for(Method m : methods){ m.genByteCode(_cg, this); } InstructionList fieldInitializations = new InstructionList(); for(FieldDeclaration f : fieldDeclarations){ fieldInitializations.append(f.genByteCode(_cg, typeinferenceResults.getTypeReconstructions().get(0))); } //Die Konstruktoren müssen die Feld initialisierungswerte beinhalten: for(Constructor c : constructors){ c.genByteCode(_cg, fieldInitializations); } return new ByteCodeResult(_cg); } public JavaClassName getName() { return name; } public Modifiers getModifiers() { return this.modifiers; } /** * Liefert die AccessFlags fuer den Bytecode zurueck. */ public short getAccessFlags() { short ret = 0; if (modifiers != null) { ret = modifiers.calculate_access_flags(); } return ret; } public Menge getSuperInterfaces() { return superif; } private Block class_block; private Hashtable parahash = new Hashtable(); // parametrisierten Attrib. werden mit den Paramet.aus paralist verk. private TypeAssumptions typeAssumptions = null;//muss mit null Initialisiert werden. Darf nur über getTypeAssumptions abgerufen werden. private Menge fielddecl = new Menge(); private GenericDeclarationList genericClassParameters; private int offset; private RefType superClass; public Menge getFields() { return fielddecl; } // ino.method.get_ParaList.23101.definition public List get_ParaList() // ino.end // ino.method.get_ParaList.23101.body { //if(this.paralist == null)return new Menge(); return this.getGenericParameter(); } // ino.end // ino.method.set_ParaHash.23104.definition public void set_ParaHash(Hashtable hash) // ino.end // ino.method.set_ParaHash.23104.body { this.parahash = hash; } // ino.end // ino.method.get_ParaHash.23107.definition public Hashtable get_ParaHash() // ino.end // ino.method.get_ParaHash.23107.body { return this.parahash; } ///////////////////////////////////////////////////////////////////////// // TypeReconstructionAlgorithmus ///////////////////////////////////////////////////////////////////////// // ino.method.TRProg.23110.defdescription type=javadoc /** * 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 */ // ino.end // ino.method.TRProg.23110.definition public ConstraintsSet typeReconstruction(TypeAssumptions globalAssumptions) // ino.end // ino.method.TRProg.23110.body { /* */ ////////////////////////////// // 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 superclassid.toString() + body.toString(); //geaendert PL 07-07-28 return name.getName(); } 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 String printJavaCode(TypeinferenceResultSet reconstructionResult){ JavaCodeResult ret = new JavaCodeResult("class "); JavaCodeResult classBodyCode = new JavaCodeResult(); if(this.modifiers!=null)classBodyCode.attach(this.modifiers.printJavaCode(reconstructionResult.getUnifiedConstraints())).attach(" "); classBodyCode.attach(this.name + " extends ").attach(this.superClass.printJavaCode(reconstructionResult.getUnifiedConstraints())).attach("\n"); JavaCodeResult bodyString = new JavaCodeResult("{\n"); for(Field field : this.fielddecl)bodyString.attach( field.printJavaCode(reconstructionResult.getUnifiedConstraints()) ).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.getUnifiedConstraints())); if(it.hasNext())ret.attach(", "); } ret.attach(">"); } String stringReturn = ret.attach(classBodyCode).toString(); return stringReturn; } /** * Errechnet die Generischen Parameter der Klasse für diese Klasse. * Die berechneten Variablen werden anschließend in die this.genericTypeVars eingesetzt. Dabei werden alte genericTypeVars überschrieben. * @param tphs : Alle übriggebliebenen TypePLaceholder private void createGenericTypeVars(Menge tphs){ this.genericClassParameters = new GenericDeclarationList(new Menge()); for(TypePlaceholder tph : tphs){ GenericTypeVar toAdd = new GenericTypeVar(tph,this.getOffset()); if(!this.genericClassParameters.contains(toAdd))this.genericClassParameters.add(toAdd); } } */ /** * Errechnet die Generischen Parameter der Klasse für diese Klasse. * Die berechneten Variablen werden anschließend in die this.genericTypeVars eingesetzt. Dabei werden alte genericTypeVars überschrieben. * @param reconstructionResult public void createGenericTypeVars(TypeinferenceResultSet reconstructionResult){ this.genericClassParameters = new Menge(); for(Pair pair : reconstructionResult.getUnifiedConstraints()){ if(pair.TA2 instanceof TypePlaceholder && pair.TA1 instanceof TypePlaceholder){// if(pair.OperatorSmallerExtends() || pair.OperatorSmaller()){ Type ta1=reconstructionResult.getUnifiedConstraints().getTypeEqualTo(pair.TA1); Type ta2=reconstructionResult.getUnifiedConstraints().getTypeEqualTo(pair.TA2); this.genericClassParameters.add(new GenericTypeVar(new Pair(ta1,ta2),this.getOffset())); } } for(Pair pair : reconstructionResult.getConstraints()){ if( ! reconstructionResult.getUnifiedConstraints().contains(pair.TA1)){ this.genericClassParameters.add(new GenericTypeVar(pair.TA1,this.getOffset())); } if( ! reconstructionResult.getUnifiedConstraints().contains(pair.TA2)){ this.genericClassParameters.add(new GenericTypeVar(pair.TA2, this.getOffset())); } } } */ 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() { /* Menge parameter = new Menge(); for(Type param : this.get_ParaList()){ parameter.add(((GenericTypeVar)param).getTypePlaceHolder());//(TypePlaceholder.fresh()); //Hier ist kein ReplacementListener notwendig. Der Typ soll nie eingesetzt werden. Der TPH wird nur gebraucht, damit das Unifizieren funktioniert. } */ 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 SyntaxTreeNode getParent() { return this; } @Override public Menge getChildren() { Menge ret = new Menge(); //for(Field f : this.getFields()){ // ret.add(f); //} ret.addAll(this.getFields()); ret.addAll(this.get_ParaList()); ret.addAll(this.getGenericParameter()); 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 Menge getGenericParameter() { if(this.genericClassParameters == null)return new Menge(); return this.genericClassParameters.getMenge(); } @Override public String getDescription(){ return "class "+this.getName(); } @Override public int getVariableLength() { // TODO Auto-generated method stub return 0; } @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 false; } /* private Collection getGenericClasses() { Collection results = new Menge<>(); for(Field field : this.fielddecl){ Type type = field.getType(); //Der Type des Feldes if(type instanceof RefType){ RefType refType = (RefType) type; if(!refType.getCombinedType(null).equals(refType.get_Name().replace(".", "%"))){ results.addAll(generateGenericClass(refType.getCombinedType(null), new Class("java/util/Vector",-1))); } } if(field instanceof Method){ Method method = (Method) field; ParameterList parameterList = method.getParameterList(); //Die Typen der Methodenparameter for(FormalParameter parameter: parameterList){ Type parameterType = parameter.getType(); if(parameterType instanceof RefType){ RefType refType = (RefType) parameterType; if(!refType.getCombinedType(null).equals(refType.get_Name().replace(".", "%"))){ results.addAll(generateGenericClass(refType.getCombinedType(null), new Class("java/util/Vector",-1))); } } } } } return results; } */ /* private Menge generateGenericClass(String name, Class superClass){ //TODO: bytecode -- Generics hinzuf�gen //Type superClassType = superClass.getType(); //TODO: bytecode //ClassGenerator genericClassGenerator = new ClassGenerator(name, superClassType, name + ".java", Constants.ACC_PUBLIC , new String[] { }, new TypeinferenceResultSet(null, null, null)); //TODO: bytecode -- Namen der neuen Klasse Class generatedClass = new Class(name, 0); //TODO: bytecode -- alle Konstruktoren generieren Block konstruktorBlock = new Block(); konstruktorBlock.setType(new de.dhbwstuttgart.syntaxtree.type.Void(konstruktorBlock, 0)); konstruktorBlock.statements.add(new SuperCall(konstruktorBlock)); Constructor standardKonstruktor = new Constructor(Method.createEmptyMethod(konstruktorBlock, name, superClass), superClass); standardKonstruktor.parserPostProcessing(generatedClass); generatedClass.addField(standardKonstruktor); return generatedClass.genByteCode(new TypeinferenceResultSet(generatedClass, new Menge<>(), new ResultSet())); } */ } // ino.end