/** * */ package soottocfg.cfg.variable; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import soottocfg.cfg.type.ReferenceType; import soottocfg.cfg.type.TypeType; /** * @author schaef * Global variable to present a Java class (e.g, String). */ public class ClassVariable extends Variable { private static final long serialVersionUID = -1647842783828780974L; private final Set<ClassVariable> parentConstants; private List<Variable> associatedFields, finalFields; public ClassVariable(String name, Collection<ClassVariable> parents) { super(name, new TypeType(), true, true); //TODO, its actually not reference type. parentConstants = new HashSet<ClassVariable>(); parentConstants.addAll(parents); associatedFields = new LinkedList<Variable>(); finalFields = new LinkedList<Variable>(); //add all fields from the super class for (ClassVariable parent : parents) { for (Variable pfield : parent.getAssociatedFields()) { if (!hasField(pfield.getName())) { Variable v = new Variable(pfield.getName(), pfield.getType(), pfield.isConstant(), pfield.isUnique()); associatedFields.add(v); if (v.isConstant()) { finalFields.add(v); } } } } } public void setType(ReferenceType rt) { this.type = rt; } public String getName() { return this.variableName; } public Collection<ClassVariable> getParents() { return Collections.unmodifiableCollection(parentConstants); } public void addFields(List<Variable> fields) { for (Variable f : fields) { if (!hasField(f.getName())) { Variable v = new Variable(f.getName(), f.getType(), f.isConstant(), f.isUnique()); associatedFields.add(v); if (v.isConstant()) { finalFields.add(v); } } else { //warn about that. } } } public Variable[] getAssociatedFields() { return associatedFields.toArray(new Variable[associatedFields.size()]); } /** * Returns the subset of fields that are final. Note that these * fields are also part of getAssociatedFields(). * @return */ public Variable[] getFinalFields() { return finalFields.toArray(new Variable[finalFields.size()]); } public boolean hasField(String fname) { for (Variable v : associatedFields) { if (v.getName().equals(fname)) { return true; } } return false; } public int findField(String fname) { for (int i=0; i<this.associatedFields.size();i++) { if (associatedFields.get(i).getName().equals(fname)) { return i; } } throw new RuntimeException("Field not found "+fname); } @Override public String toString() { return this.variableName; } public boolean subclassOf(ClassVariable cls) { List<ClassVariable> todo = new LinkedList<ClassVariable>(); todo.add(this); while (!todo.isEmpty()) { ClassVariable cv = todo.remove(0); if (cv==cls) return true; if (cv.getParents()!=null) { todo.addAll(cv.getParents()); } } return false; } public boolean superclassOf(ClassVariable cls) { return cls.subclassOf(this); } @Override public boolean equals(Object obj) { if (obj == null) return false; if (this.getClass() == obj.getClass()) { ClassVariable other = (ClassVariable) obj; return this.variableName.equals(other.variableName) && this.type.equals(other.type) && this.associatedFields.containsAll(other.associatedFields) && this.finalFields.containsAll(other.finalFields) && this.parentConstants.containsAll(other.parentConstants); } return false; } @Override public int hashCode() { int result = 42; result = 37 * result + this.variableName.hashCode(); result = 37 * result + this.type.hashCode(); result = 37 * result + this.associatedFields.hashCode(); result = 37 * result + this.finalFields.hashCode(); result = 37 * result + this.parentConstants.hashCode(); return result; } }