blob: 120347eb5df66509085258f27ca2d5692c938a3e [file] [log] [blame]
package org.checkerframework.dataflow.analysis;
import java.util.Map;
import java.util.StringJoiner;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.plumelib.util.StringsPlume;
/**
* Implementation of a {@link TransferResult} with just one non-exceptional store. The result of
* {@code getThenStore} and {@code getElseStore} is equal to the only underlying store.
*
* @param <V> type of the abstract value that is tracked
* @param <S> the store type used in the analysis
*/
public class RegularTransferResult<V extends AbstractValue<V>, S extends Store<S>>
extends TransferResult<V, S> {
/** The regular result store. */
protected final S store;
/**
* Whether the store changed; see {@link
* org.checkerframework.dataflow.analysis.TransferResult#storeChanged}.
*/
private final boolean storeChanged;
/**
* Create a new {@link #RegularTransferResult(AbstractValue, Store, Map, boolean)}, using {@code
* null} for {@link org.checkerframework.dataflow.analysis.TransferResult#exceptionalStores}.
*
* <p><em>Exceptions</em>: If the corresponding {@link
* org.checkerframework.dataflow.cfg.node.Node} throws an exception, then it is assumed that no
* special handling is necessary and the store before the corresponding {@link
* org.checkerframework.dataflow.cfg.node.Node} will be passed along any exceptional edge.
*
* <p><em>Aliasing</em>: {@code resultStore} is not allowed to be used anywhere outside of this
* class (including use through aliases). Complete control over the object is transferred to this
* class.
*
* @param value the abstract value produced by the transfer function
* @param resultStore regular result store
* @param storeChanged whether the store changed; see {@link
* org.checkerframework.dataflow.analysis.TransferResult#storeChanged}
* @see #RegularTransferResult(AbstractValue, Store, Map, boolean)
*/
public RegularTransferResult(@Nullable V value, S resultStore, boolean storeChanged) {
this(value, resultStore, null, storeChanged);
}
/**
* Create a new {@link #RegularTransferResult(AbstractValue, Store, Map, boolean)}, using {@code
* null} for {@link org.checkerframework.dataflow.analysis.TransferResult#exceptionalStores} and
* {@code false} for {@link org.checkerframework.dataflow.analysis.TransferResult#storeChanged}.
*
* @param value the abstract value produced by the transfer function
* @param resultStore regular result store
* @see #RegularTransferResult(AbstractValue, Store, Map, boolean)
*/
public RegularTransferResult(@Nullable V value, S resultStore) {
this(value, resultStore, false);
}
/**
* Create a new {@link #RegularTransferResult(AbstractValue, Store, Map, boolean)}, using {@code
* false} for {@link org.checkerframework.dataflow.analysis.TransferResult#storeChanged}.
*
* @param value the abstract value produced by the transfer function
* @param resultStore the regular result store
* @param exceptionalStores the stores in case the basic block throws an exception, or null if the
* basic block does not throw any exceptions
* @see #RegularTransferResult(AbstractValue, Store, Map, boolean)
*/
public RegularTransferResult(
@Nullable V value, S resultStore, Map<TypeMirror, S> exceptionalStores) {
this(value, resultStore, exceptionalStores, false);
}
/**
* Create a {@code TransferResult} with {@code resultStore} as the resulting store. If the
* corresponding {@link org.checkerframework.dataflow.cfg.node.Node} is a boolean node, then
* {@code resultStore} is used for both the 'then' and 'else' edge.
*
* <p><em>Exceptions</em>: If the corresponding {@link
* org.checkerframework.dataflow.cfg.node.Node} throws an exception, then the corresponding store
* in {@code exceptionalStores} is used. If no exception is found in {@code exceptionalStores},
* then it is assumed that no special handling is necessary and the store before the corresponding
* {@link org.checkerframework.dataflow.cfg.node.Node} will be passed along any exceptional edge.
*
* <p><em>Aliasing</em>: {@code resultStore} and any store in {@code exceptionalStores} are not
* allowed to be used anywhere outside of this class (including use through aliases). Complete
* control over the objects is transferred to this class.
*
* @param value the abstract value produced by the transfer function
* @param resultStore the regular result store
* @param exceptionalStores the stores in case the basic block throws an exception, or null if the
* basic block does not throw any exceptions
* @param storeChanged see {@link
* org.checkerframework.dataflow.analysis.TransferResult#storeChanged}
*/
public RegularTransferResult(
@Nullable V value,
S resultStore,
@Nullable Map<TypeMirror, S> exceptionalStores,
boolean storeChanged) {
super(value, exceptionalStores);
this.store = resultStore;
this.storeChanged = storeChanged;
}
/** The regular result store. */
@Override
public S getRegularStore() {
return store;
}
@Override
public S getThenStore() {
return store;
}
@Override
public S getElseStore() {
// copy the store such that it is the same as the result of getThenStore
// (that is, identical according to equals), but two different objects.
return store.copy();
}
@Override
public boolean containsTwoStores() {
return false;
}
@Override
public String toString() {
StringJoiner result = new StringJoiner(System.lineSeparator());
result.add("RegularTransferResult(");
result.add(" resultValue = " + StringsPlume.indentLinesExceptFirst(2, resultValue));
// "toString().trim()" works around bug where toString ends with a newline.
result.add(
" store = " + StringsPlume.indentLinesExceptFirst(2, store.toString().trim()) + ")");
return result.toString();
}
/**
* See {@link org.checkerframework.dataflow.analysis.TransferResult#storeChanged()}.
*
* @see org.checkerframework.dataflow.analysis.TransferResult#storeChanged()
*/
@Override
public boolean storeChanged() {
return storeChanged;
}
}