package org.checkerframework.checker.index;
import com.sun.source.tree.Tree;
import java.util.Collections;
import java.util.List;
import javax.lang.model.element.AnnotationMirror;
import org.checkerframework.common.value.ValueAnnotatedTypeFactory;
import org.checkerframework.common.value.qual.IntVal;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.javacutil.AnnotationUtils;
/** A collection of utility functions used by several Index Checker subcheckers. */
public class IndexUtil {
/**
* Gets the value field of an annotation with a list of strings in its value field. Null is
* returned if the annotation has no value field.
*
* <p>For the Index Checker, this will get a list of array names from an Upper Bound or SameLen
* annotation. making this safe to call on any Upper Bound or SameLen annotation.
*/
public static List<String> getValueOfAnnotationWithStringArgument(AnnotationMirror anno) {
if (!AnnotationUtils.hasElementValue(anno, "value")) {
return null;
}
return AnnotationUtils.getElementValueArray(anno, "value", String.class, true);
}
/**
* Get the list of possible values from an AnnotatedTypeMirror containing an IntVal. Empty list
* means no possible values (dead code). Returns null if the AnnotatedTypeMirror doesn't contain
* an IntVal.
*/
public static List<Long> getPossibleValues(AnnotatedTypeMirror valueType) {
return ValueAnnotatedTypeFactory.getIntValues(valueType.getAnnotation(IntVal.class));
}
/**
* Either returns the exact value of the given tree according to the Constant Value Checker, or
* null if the exact value is not known. This method should only be used by clients who need
* exactly one value -- such as the LBC's binary operator rules -- and not by those that need to
* know whether a valueType belongs to a particular qualifier.
*/
public static Long getExactValue(Tree tree, ValueAnnotatedTypeFactory factory) {
AnnotatedTypeMirror valueType = factory.getAnnotatedType(tree);
List<Long> possibleValues = getPossibleValues(valueType);
if (possibleValues != null && possibleValues.size() == 1) {
return possibleValues.get(0);
} else {
return null;
}
}
/**
* Finds the minimum value in a Value Checker type. If there is no information (such as when the
* list of possible values is empty or null), returns null. Otherwise, returns the smallest
* value in the list of possible values.
*/
public static Long getMinValue(Tree tree, ValueAnnotatedTypeFactory factory) {
AnnotatedTypeMirror valueType = factory.getAnnotatedType(tree);
List<Long> possibleValues = getPossibleValues(valueType);
if (possibleValues != null && possibleValues.size() != 0) {
return Collections.min(possibleValues);
} else {
return null;
}
}
/**
* Finds the maximum value in a Value Checker type. If there is no information (such as when the
* list of possible values is empty or null), returns null. Otherwise, returns the smallest
* value in the list of possible values.
*/
public static Long getMaxValue(Tree tree, ValueAnnotatedTypeFactory factory) {
AnnotatedTypeMirror valueType = factory.getAnnotatedType(tree);
List<Long> possibleValues = getPossibleValues(valueType);
if (possibleValues != null && possibleValues.size() != 0) {
return Collections.max(possibleValues);
} else {
return null;
}
}
/**
* Queries the Value Checker to determine if there is a known minimum length for the array
* represented by {@code tree}. If not, returns null.
*/
public static Integer getMinLen(
Tree tree, ValueAnnotatedTypeFactory valueAnnotatedTypeFactory) {
AnnotatedTypeMirror minLenType = valueAnnotatedTypeFactory.getAnnotatedType(tree);
return valueAnnotatedTypeFactory.getMinLenValue(minLenType);
}
}