/**
*
*/
package soottocfg.cfg.statement;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Verify;
import soottocfg.cfg.SourceLocation;
import soottocfg.cfg.expression.Expression;
import soottocfg.cfg.expression.IdentifierExpression;
import soottocfg.cfg.variable.ClassVariable;
import soottocfg.cfg.variable.Variable;
/**
* @author schaef
*
*/
public class PushStatement extends Statement {
private static final long serialVersionUID = 5776310555422969945L;
private final ClassVariable classConstant;
private IdentifierExpression object;
private final List<Expression> right;
private final List<Expression> ghostExpressions;
private final int id;
private static int nextID = 0;
/**
* @param loc
*/
public PushStatement(SourceLocation loc, ClassVariable c, IdentifierExpression obj, List<Expression> rhs, int id) {
this(loc, c, obj, rhs, null, id);
}
public PushStatement(SourceLocation loc, ClassVariable c, IdentifierExpression obj, List<Expression> rhs, List<Expression> ghostExpressions, int id) {
super(loc);
this.ghostExpressions = new LinkedList<Expression>();
if (ghostExpressions!=null) {
this.ghostExpressions.addAll(ghostExpressions);
}
classConstant = c;
object = obj;
right = new LinkedList<Expression>(rhs);
this.id = id;
verifySize();
}
private void verifySize() {
if (classConstant.getAssociatedFields().length != right.size()) {
StringBuilder err = new StringBuilder();
err.append(object);
err.append(" has fields ");
String comma = "";
err.append("[");
for (Variable cv : classConstant.getAssociatedFields()) {
err.append(comma);
comma = ", ";
err.append(cv.getName()+":"+cv.getType());
}
err.append("] but is assigned to ");
err.append("[");
comma = "";
for (Expression e : right) {
err.append(comma);
comma = ", ";
err.append(e+":"+e.getType());
}
err.append("]");
Verify.verify(false, err.toString());
}
}
public PushStatement(SourceLocation loc, ClassVariable c, IdentifierExpression obj, List<Expression> rhs) {
this(loc, c, obj, rhs, nextID());
}
public List<Expression> getGhostExpressions() {
return this.ghostExpressions;
}
// had to put this in a method to silence findBugs...
private static int nextID() {
return ++nextID;
}
public ClassVariable getClassSignature() {
return classConstant;
}
public Expression getObject() {
return object;
}
public List<Expression> getRight() {
return right;
}
public int getID() {
return id;
}
@Override
public Set<IdentifierExpression> getUseIdentifierExpressions() {
Set<IdentifierExpression> used = new HashSet<IdentifierExpression>();
for (Expression e : right) {
used.addAll(e.getUseIdentifierExpressions());
}
for (Expression e: ghostExpressions) {
used.addAll(e.getUseIdentifierExpressions());
}
//TODO: I'm not sure if a push is a use or a def of 'object' ... or both?
used.add(object);
return used;
}
@Override
public Set<IdentifierExpression> getDefIdentifierExpressions() {
Set<IdentifierExpression> res = new HashSet<IdentifierExpression>();
// res.add(object);
return res;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("push_");
sb.append(id);
sb.append("(");
sb.append(classConstant.getName());
sb.append(", ");
sb.append(object);
for (Expression e : this.ghostExpressions) {
sb.append(", ");
sb.append(e);
}
sb.append(", [");
String comma = "";
for (Expression v : right) {
sb.append(comma);
sb.append(v);
comma = ", ";
}
sb.append("]");
sb.append(")");
return sb.toString();
}
// TODO check where this is used and what to do with ID
@Override
public Statement deepCopy() {
List<Expression> rightCopy = new LinkedList<Expression>();
for (Expression e : right) {
rightCopy.add(e.deepCopy());
}
List<Expression> ghostCopy = new LinkedList<Expression>();
for (Expression e : ghostExpressions) {
ghostCopy.add(e.deepCopy());
}
return new PushStatement(getSourceLocation(), classConstant, object.deepCopy(), rightCopy, ghostCopy, this.id);
}
@Override
public PushStatement substitute(Map<Variable, Variable> subs) {
List<Expression> rightCopy = new LinkedList<Expression>();
for (Expression e : right) {
rightCopy.add(e.substitute(subs));
}
List<Expression> ghostCopy = new LinkedList<Expression>();
for (Expression e : ghostExpressions) {
ghostCopy.add(e.substitute(subs));
}
return new PushStatement(getSourceLocation(), classConstant, object.substitute(subs), rightCopy, ghostCopy, this.id);
}
@Override
public PushStatement substituteVarWithExpression(Map<Variable, Expression> subs) {
List<Expression> rightCopy = new LinkedList<Expression>();
for (Expression e : right) {
rightCopy.add(e.substituteVarWithExpression(subs));
}
List<Expression> ghostCopy = new LinkedList<Expression>();
for (Expression e : ghostExpressions) {
ghostCopy.add(e.substituteVarWithExpression(subs));
}
// Verify.verify(!subs.containsKey(object.getVariable()));
return new PushStatement(getSourceLocation(), classConstant, object.deepCopy(), rightCopy, ghostCopy, this.id);
}
// @Override
// public boolean equals(Object o) {
// if (!(o instanceof PushStatement))
// return false;
// PushStatement other = (PushStatement) o;
// return this.id == other.id;
// }
//
// @Override
// public int hashCode() {
// return id;
// }
}