blob: 0abe4528677b5c510e032b59c1a1cd7900bb9c14 [file] [log] [blame]
package org.checkerframework.dataflow.livevariable;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.StringJoiner;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.analysis.Store;
import org.checkerframework.dataflow.cfg.node.BinaryOperationNode;
import org.checkerframework.dataflow.cfg.node.FieldAccessNode;
import org.checkerframework.dataflow.cfg.node.InstanceOfNode;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.TernaryExpressionNode;
import org.checkerframework.dataflow.cfg.node.TypeCastNode;
import org.checkerframework.dataflow.cfg.node.UnaryOperationNode;
import org.checkerframework.dataflow.cfg.visualize.CFGVisualizer;
import org.checkerframework.dataflow.expression.JavaExpression;
import org.checkerframework.javacutil.BugInCF;
/** A live variable store contains a set of live variables represented by nodes. */
public class LiveVarStore implements Store<LiveVarStore> {
/** A set of live variable abstract values. */
private final Set<LiveVarValue> liveVarValueSet;
/** Create a new LiveVarStore. */
public LiveVarStore() {
liveVarValueSet = new LinkedHashSet<>();
}
/**
* Create a new LiveVarStore.
*
* @param liveVarValueSet a set of live variable abstract values
*/
public LiveVarStore(Set<LiveVarValue> liveVarValueSet) {
this.liveVarValueSet = liveVarValueSet;
}
/**
* Add the information of a live variable into the live variable set.
*
* @param variable a live variable
*/
public void putLiveVar(LiveVarValue variable) {
liveVarValueSet.add(variable);
}
/**
* Remove the information of a live variable from the live variable set.
*
* @param variable a live variable
*/
public void killLiveVar(LiveVarValue variable) {
liveVarValueSet.remove(variable);
}
/**
* Add the information of live variables in an expression to the live variable set.
*
* @param expression a node
*/
public void addUseInExpression(Node expression) {
// TODO Do we need a AbstractNodeScanner to do the following job?
if (expression instanceof LocalVariableNode || expression instanceof FieldAccessNode) {
LiveVarValue liveVarValue = new LiveVarValue(expression);
putLiveVar(liveVarValue);
} else if (expression instanceof UnaryOperationNode) {
UnaryOperationNode unaryNode = (UnaryOperationNode) expression;
addUseInExpression(unaryNode.getOperand());
} else if (expression instanceof TernaryExpressionNode) {
TernaryExpressionNode ternaryNode = (TernaryExpressionNode) expression;
addUseInExpression(ternaryNode.getConditionOperand());
addUseInExpression(ternaryNode.getThenOperand());
addUseInExpression(ternaryNode.getElseOperand());
} else if (expression instanceof TypeCastNode) {
TypeCastNode typeCastNode = (TypeCastNode) expression;
addUseInExpression(typeCastNode.getOperand());
} else if (expression instanceof InstanceOfNode) {
InstanceOfNode instanceOfNode = (InstanceOfNode) expression;
addUseInExpression(instanceOfNode.getOperand());
} else if (expression instanceof BinaryOperationNode) {
BinaryOperationNode binaryNode = (BinaryOperationNode) expression;
addUseInExpression(binaryNode.getLeftOperand());
addUseInExpression(binaryNode.getRightOperand());
}
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof LiveVarStore)) {
return false;
}
LiveVarStore other = (LiveVarStore) obj;
return other.liveVarValueSet.equals(this.liveVarValueSet);
}
@Override
public int hashCode() {
return this.liveVarValueSet.hashCode();
}
@Override
public LiveVarStore copy() {
return new LiveVarStore(new HashSet<>(liveVarValueSet));
}
@Override
public LiveVarStore leastUpperBound(LiveVarStore other) {
Set<LiveVarValue> liveVarValueSetLub =
new HashSet<>(this.liveVarValueSet.size() + other.liveVarValueSet.size());
liveVarValueSetLub.addAll(this.liveVarValueSet);
liveVarValueSetLub.addAll(other.liveVarValueSet);
return new LiveVarStore(liveVarValueSetLub);
}
/** It should not be called since it is not used by the backward analysis. */
@Override
public LiveVarStore widenedUpperBound(LiveVarStore previous) {
throw new BugInCF("wub of LiveVarStore get called!");
}
@Override
public boolean canAlias(JavaExpression a, JavaExpression b) {
return true;
}
@Override
public String visualize(CFGVisualizer<?, LiveVarStore, ?> viz) {
String key = "live variables";
if (liveVarValueSet.isEmpty()) {
return viz.visualizeStoreKeyVal(key, "none");
}
StringJoiner sjStoreVal = new StringJoiner(", ");
for (LiveVarValue liveVarValue : liveVarValueSet) {
sjStoreVal.add(liveVarValue.toString());
}
return viz.visualizeStoreKeyVal(key, sjStoreVal.toString());
}
@Override
public String toString() {
return liveVarValueSet.toString();
}
}