/**
*
*/
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;
}
}