blob: 11a83ba801f199272db68cb0c619a0779ad30c73 [file] [log] [blame]
package org.checkerframework.dataflow.expression;
import java.math.BigInteger;
import java.util.Objects;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.analysis.Store;
import org.checkerframework.dataflow.cfg.node.ValueLiteralNode;
import org.checkerframework.javacutil.AnnotationProvider;
import org.checkerframework.javacutil.TypesUtils;
/** JavaExpression for literals. */
public class ValueLiteral extends JavaExpression {
/** The value of the literal. */
protected final @Nullable Object value;
/** The negative of Long.MIN_VALUE, which does not fit in a long. */
private final BigInteger NEGATIVE_LONG_MIN_VALUE = new BigInteger("9223372036854775808");
/**
* Creates a ValueLiteral from the node with the given type.
*
* @param type type of the literal
* @param node the literal represents by this {@link
* org.checkerframework.dataflow.expression.ValueLiteral}
*/
public ValueLiteral(TypeMirror type, ValueLiteralNode node) {
super(type);
value = node.getValue();
}
/**
* Creates a ValueLiteral where the value is {@code value} that has the given type.
*
* @param type type of the literal
* @param value the literal value
*/
public ValueLiteral(TypeMirror type, Object value) {
super(type);
this.value = value;
}
/**
* Returns the negation of this literal. Throws an exception if negation is not possible.
*
* @return the negation of this literal
*/
public ValueLiteral negate() {
if (TypesUtils.isIntegralPrimitive(type)) {
if (value == null) {
throw new Error("null value of integral type " + type);
}
return new ValueLiteral(type, negateBoxedPrimitive(value));
}
throw new Error(String.format("cannot negate: %s type=%s", this, type));
}
/**
* Negate a boxed primitive.
*
* @param o a boxed primitive
* @return a boxed primitive that is the negation of the argument
*/
private Object negateBoxedPrimitive(Object o) {
if (value instanceof Byte) {
return (byte) -(Byte) value;
}
if (value instanceof Short) {
return (short) -(Short) value;
}
if (value instanceof Integer) {
return -(Integer) value;
}
if (value instanceof Long) {
return -(Long) value;
}
if (value instanceof Float) {
return -(Float) value;
}
if (value instanceof Double) {
return -(Double) value;
}
if (value instanceof BigInteger) {
assert value.equals(NEGATIVE_LONG_MIN_VALUE);
return Long.MIN_VALUE;
}
throw new Error("Cannot be negated: " + o + " " + o.getClass());
}
/**
* Returns the value of this literal.
*
* @return the value of this literal
*/
public @Nullable Object getValue() {
return value;
}
@Override
public boolean containsOfClass(Class<? extends JavaExpression> clazz) {
return getClass() == clazz;
}
@Override
public boolean isDeterministic(AnnotationProvider provider) {
return true;
}
@Override
public boolean isUnassignableByOtherCode() {
return true;
}
@Override
public boolean isUnmodifiableByOtherCode() {
return true;
}
@Override
public boolean syntacticEquals(JavaExpression je) {
return this.equals(je);
}
@Override
public boolean containsSyntacticEqualJavaExpression(JavaExpression other) {
return this.syntacticEquals(other);
}
@Override
public boolean containsModifiableAliasOf(Store<?> store, JavaExpression other) {
return false; // not modifiable
}
/// java.lang.Object methods
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof ValueLiteral)) {
return false;
}
ValueLiteral other = (ValueLiteral) obj;
// TODO: Can this string comparison be cleaned up?
// Cannot use Types.isSameType(type, other.type) because we don't have a Types object.
return type.toString().equals(other.type.toString()) && Objects.equals(value, other.value);
}
@Override
public String toString() {
if (TypesUtils.isString(type)) {
return "\"" + value + "\"";
} else if (type.getKind() == TypeKind.LONG) {
assert value != null : "@AssumeAssertion(nullness): invariant";
return value.toString() + "L";
} else if (type.getKind() == TypeKind.CHAR) {
return "\'" + value + "\'";
}
return value == null ? "null" : value.toString();
}
@Override
public int hashCode() {
return Objects.hash(value, type.toString());
}
@Override
public <R, P> R accept(JavaExpressionVisitor<R, P> visitor, P p) {
return visitor.visitValueLiteral(this, p);
}
}