package de.dhbwstuttgart.syntaxtree; import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.type.GenericRefType; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; import org.antlr.v4.runtime.Token; import java.lang.reflect.Modifier; import java.util.*; /** * Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces */ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { private Boolean methodAdded = false; // wird benoetigt bei in JavaTXCompiler.getConstraints() protected int modifiers; protected JavaClassName name; private final String fileName; private List<Field> fields = new ArrayList<>(); private Optional<Constructor> fieldInitializations; // PL 2018-11-24: Noetig, um Bytecode fuer initializators nur einmal zu erzeugen private Optional<Method> staticInitializer; private List<Method> methods = new ArrayList<>(); private GenericDeclarationList genericClassParameters; private RefType superClass; protected boolean isInterface; protected boolean isFunctionalInterface; private List<RefType> implementedInterfaces; private List<RefType> permittedSubtypes; private List<Constructor> constructors; public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, Boolean isFunctionalInterface, List<RefType> implementedInterfaces, List<RefType> permittedSubtypes, Token offset, String fileName) { super(offset); if (isInterface) { modifiers |= Modifier.INTERFACE | Modifier.ABSTRACT; } this.modifiers = modifiers; this.name = name; this.fields = fielddecl; this.fieldInitializations = fieldInitializations; this.staticInitializer = staticInitializer; this.genericClassParameters = genericClassParameters; this.superClass = superClass; this.isInterface = isInterface; this.isFunctionalInterface= isFunctionalInterface; this.implementedInterfaces = implementedInterfaces; this.permittedSubtypes = permittedSubtypes; this.methods = methods; this.constructors = constructors; this.fileName = fileName; } /* * erzeugt fuer Fields, Konstruktoren und Methoden neue ArrayList-Objekte alle anderen Datenobjekte werden nur kopiert. */ public ClassOrInterface(ClassOrInterface cl) { super(cl.getOffset()); this.modifiers = cl.modifiers; this.name = cl.name; this.fields = new ArrayList<>(cl.fields); this.fieldInitializations = cl.fieldInitializations; this.staticInitializer = cl.staticInitializer; this.genericClassParameters = cl.genericClassParameters; this.superClass = cl.superClass; this.isInterface = cl.isInterface; this.isFunctionalInterface= cl.isFunctionalInterface; this.implementedInterfaces = cl.implementedInterfaces; this.methods = new ArrayList<>(cl.methods); this.constructors = new ArrayList<>(cl.constructors); this.fileName = cl.fileName; } public String getFileName() { return fileName; } public Optional<Field> getField(String name) { // TODO This should be a map return fields.stream().filter(field -> field.getName().equals(name)).findFirst(); } public Optional<Method> getStaticInitializer() { return staticInitializer; } public boolean isInterface() { return (Modifier.INTERFACE & this.getModifiers()) != 0; } public boolean isFunctionalInterface() { return this.isFunctionalInterface; } // Gets if it is added public Boolean areMethodsAdded() { return methodAdded; } // Sets that it is added public void setMethodsAdded() { methodAdded = true; } // Gets class name public JavaClassName getClassName() { return this.name; } // Get modifiers public int getModifiers() { return this.modifiers; } public List<Field> getFieldDecl() { return this.fields; } public Optional<Constructor> getfieldInitializations() { return this.fieldInitializations; } public List<Method> getMethods() { return this.methods; } /* * public RefType getType() { return generateTypeOfClass(this.getClassName(), this.getGenerics(), this.getOffset()); } */ // TODO: Das hier ist ein Problem. Je nach Kontext wird hier ein anderer Typ benötigt public static RefType generateTypeOfClass(JavaClassName name, GenericDeclarationList genericsOfClass, Token offset) { // Hier wird immer ein generischer Typ generiert, also mit Type placeholdern List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>(); for (GenericTypeVar genericTypeVar : genericsOfClass) { // params.add(genericTypeVar.getTypePlaceholder()); params.add(TypePlaceholder.fresh(offset)); } return new RefType(name, params, offset); } /** * * @return die aktuelle Klasse als RefType */ public RefType generateTypeOfThisClass() { List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>(); for (GenericTypeVar genericTypeVar : this.getGenerics()) { // params.add(genericTypeVar.getTypePlaceholder()); params.add(new GenericRefType(genericTypeVar.getName(), new NullToken())); } return new RefType(name, params, new NullToken()); } /** * Die Superklasse im Kontext dieser ClassOrInterface Das bedeutet, dass generische Variablen als GenericRefTypes dargestellt sind */ public RefType getSuperClass() { return superClass; } public GenericDeclarationList getGenerics() { return this.genericClassParameters; } @Override public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { return null; } public List<Constructor> getConstructors() { return constructors; } @Override public void accept(ASTVisitor visitor) { visitor.visit(this); } public Collection<RefType> getSuperInterfaces() { return implementedInterfaces; } public String toString() { return this.name.toString() + this.genericClassParameters.toString(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ClassOrInterface that = (ClassOrInterface) o; return Objects.equals(name, that.name); } @Override public int hashCode() { return Objects.hash(name); } }