use of org.checkerframework.dataflow.expression.ArrayAccess in project checker-framework by typetools.
the class ValueAnnotatedTypeFactory method getMinLenFromString.
/**
* Returns the minimum length of an array expression or 0 if the min length is unknown.
*
* @param sequenceExpression Java expression
* @param tree expression tree or variable declaration
* @param currentPath path to local scope
* @return min length of sequenceExpression or 0
*/
public int getMinLenFromString(String sequenceExpression, Tree tree, TreePath currentPath) {
AnnotationMirror lengthAnno;
JavaExpression expressionObj;
try {
expressionObj = parseJavaExpressionString(sequenceExpression, currentPath);
} catch (JavaExpressionParseException e) {
// ignore parse errors and return 0.
return 0;
}
if (expressionObj instanceof ValueLiteral) {
ValueLiteral sequenceLiteral = (ValueLiteral) expressionObj;
Object sequenceLiteralValue = sequenceLiteral.getValue();
if (sequenceLiteralValue instanceof String) {
return ((String) sequenceLiteralValue).length();
}
} else if (expressionObj instanceof ArrayCreation) {
ArrayCreation arrayCreation = (ArrayCreation) expressionObj;
// This is only expected to support array creations in varargs methods
return arrayCreation.getInitializers().size();
} else if (expressionObj instanceof ArrayAccess) {
List<? extends AnnotationMirror> annoList = expressionObj.getType().getAnnotationMirrors();
for (AnnotationMirror anno : annoList) {
String ANNO_NAME = AnnotationUtils.annotationName(anno);
if (ANNO_NAME.equals(MINLEN_NAME)) {
return getMinLenValue(canonicalAnnotation(anno));
} else if (ANNO_NAME.equals(ARRAYLEN_NAME) || ANNO_NAME.equals(ARRAYLENRANGE_NAME)) {
return getMinLenValue(anno);
}
}
}
lengthAnno = getAnnotationFromJavaExpression(expressionObj, tree, ArrayLenRange.class);
if (lengthAnno == null) {
lengthAnno = getAnnotationFromJavaExpression(expressionObj, tree, ArrayLen.class);
}
if (lengthAnno == null) {
lengthAnno = getAnnotationFromJavaExpression(expressionObj, tree, StringVal.class);
}
if (lengthAnno == null) {
// Could not find a more precise type, so return 0;
return 0;
}
return getMinLenValue(lengthAnno);
}
use of org.checkerframework.dataflow.expression.ArrayAccess in project checker-framework by typetools.
the class LockStore method insertLockPossiblyHeld.
/*
* Insert an annotation exactly, without regard to whether an annotation was already present.
* This is only done for @LockPossiblyHeld. This is not sound for other type qualifiers.
*/
public void insertLockPossiblyHeld(JavaExpression je) {
if (je.containsUnknown()) {
// Expressions containing unknown expressions are not stored.
return;
}
if (je instanceof LocalVariable) {
LocalVariable localVar = (LocalVariable) je;
CFValue current = localVariableValues.get(localVar);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
localVariableValues.put(localVar, value);
}
} else if (je instanceof FieldAccess) {
FieldAccess fieldAcc = (FieldAccess) je;
CFValue current = fieldValues.get(fieldAcc);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
fieldValues.put(fieldAcc, value);
}
} else if (je instanceof MethodCall) {
MethodCall method = (MethodCall) je;
CFValue current = methodValues.get(method);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
methodValues.put(method, value);
}
} else if (je instanceof ArrayAccess) {
ArrayAccess arrayAccess = (ArrayAccess) je;
CFValue current = arrayValues.get(arrayAccess);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
arrayValues.put(arrayAccess, value);
}
} else if (je instanceof ThisReference) {
thisValue = changeLockAnnoToTop(je, thisValue);
} else if (je instanceof ClassName) {
ClassName className = (ClassName) je;
CFValue current = classValues.get(className);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
classValues.put(className, value);
}
} else {
// No other types of expressions need to be stored.
}
}
use of org.checkerframework.dataflow.expression.ArrayAccess in project checker-framework by typetools.
the class CFAbstractStore method computeNewValueAndInsert.
/**
* Inserts the result of applying {@code merger} to {@code value} and the previous value for
* {@code expr}.
*
* @param expr the JavaExpression
* @param value the value of the JavaExpression
* @param merger the function used to merge {@code value} and the previous value of {@code expr}
* @param permitNondeterministic if false, does nothing if {@code expr} is nondeterministic; if
* true, permits nondeterministic expressions to be placed in the store
*/
protected void computeNewValueAndInsert(JavaExpression expr, @Nullable V value, BinaryOperator<V> merger, boolean permitNondeterministic) {
if (!shouldInsert(expr, value, permitNondeterministic)) {
return;
}
if (expr instanceof LocalVariable) {
LocalVariable localVar = (LocalVariable) expr;
V oldValue = localVariableValues.get(localVar);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
localVariableValues.put(localVar, newValue);
}
} else if (expr instanceof FieldAccess) {
FieldAccess fieldAcc = (FieldAccess) expr;
// Only store information about final fields (where the receiver is
// also fixed) if concurrent semantics are enabled.
boolean isMonotonic = isMonotonicUpdate(fieldAcc, value);
if (sequentialSemantics || isMonotonic || fieldAcc.isUnassignableByOtherCode()) {
V oldValue = fieldValues.get(fieldAcc);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
fieldValues.put(fieldAcc, newValue);
}
}
} else if (expr instanceof MethodCall) {
MethodCall method = (MethodCall) expr;
// Don't store any information if concurrent semantics are enabled.
if (sequentialSemantics) {
V oldValue = methodValues.get(method);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
methodValues.put(method, newValue);
}
}
} else if (expr instanceof ArrayAccess) {
ArrayAccess arrayAccess = (ArrayAccess) expr;
if (sequentialSemantics) {
V oldValue = arrayValues.get(arrayAccess);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
arrayValues.put(arrayAccess, newValue);
}
}
} else if (expr instanceof ThisReference) {
ThisReference thisRef = (ThisReference) expr;
if (sequentialSemantics || thisRef.isUnassignableByOtherCode()) {
V oldValue = thisValue;
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
thisValue = newValue;
}
}
} else if (expr instanceof ClassName) {
ClassName className = (ClassName) expr;
if (sequentialSemantics || className.isUnassignableByOtherCode()) {
V oldValue = classValues.get(className);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
classValues.put(className, newValue);
}
}
} else {
// No other types of expressions need to be stored.
}
}
use of org.checkerframework.dataflow.expression.ArrayAccess in project checker-framework by typetools.
the class CFAbstractStore method removeConflicting.
/**
* Remove any information in this store that might not be true any more after {@code fieldAccess}
* has been assigned a new value (with the abstract value {@code val}). This includes the
* following steps (assume that {@code fieldAccess} is of the form <em>a.f</em> for some
* <em>a</em>.
*
* <ol>
* <li value="1">Update the abstract value of other field accesses <em>b.g</em> where the field
* is equal (that is, <em>f=g</em>), and the receiver <em>b</em> might alias the receiver of
* {@code fieldAccess}, <em>a</em>. This update will raise the abstract value for such field
* accesses to at least {@code val} (or the old value, if that was less precise). However,
* this is only necessary if the field <em>g</em> is not final.
* <li value="2">Remove any abstract values for field accesses <em>b.g</em> where {@code
* fieldAccess} might alias any expression in the receiver <em>b</em>.
* <li value="3">Remove any information about method calls.
* <li value="4">Remove any abstract values an array access <em>b[i]</em> where {@code
* fieldAccess} might alias any expression in the receiver <em>a</em> or index <em>i</em>.
* </ol>
*
* @param val the abstract value of the value assigned to {@code n} (or {@code null} if the
* abstract value is not known).
*/
protected void removeConflicting(FieldAccess fieldAccess, @Nullable V val) {
final Iterator<Map.Entry<FieldAccess, V>> fieldValuesIterator = fieldValues.entrySet().iterator();
while (fieldValuesIterator.hasNext()) {
Map.Entry<FieldAccess, V> entry = fieldValuesIterator.next();
FieldAccess otherFieldAccess = entry.getKey();
V otherVal = entry.getValue();
// case 2:
if (otherFieldAccess.getReceiver().containsModifiableAliasOf(this, fieldAccess)) {
// remove information completely
fieldValuesIterator.remove();
} else // case 1:
if (fieldAccess.getField().equals(otherFieldAccess.getField())) {
if (canAlias(fieldAccess.getReceiver(), otherFieldAccess.getReceiver())) {
if (!otherFieldAccess.isFinal()) {
if (val != null) {
V newVal = val.leastUpperBound(otherVal);
entry.setValue(newVal);
} else {
// remove information completely
fieldValuesIterator.remove();
}
}
}
}
}
final Iterator<Map.Entry<ArrayAccess, V>> arrayValuesIterator = arrayValues.entrySet().iterator();
while (arrayValuesIterator.hasNext()) {
Map.Entry<ArrayAccess, V> entry = arrayValuesIterator.next();
ArrayAccess otherArrayAccess = entry.getKey();
if (otherArrayAccess.containsModifiableAliasOf(this, fieldAccess)) {
// remove information completely
arrayValuesIterator.remove();
}
}
// case 3:
methodValues.clear();
}
use of org.checkerframework.dataflow.expression.ArrayAccess in project checker-framework by typetools.
the class CFAbstractStore method removeConflicting.
/**
* Remove any information in the store that might not be true any more after {@code arrayAccess}
* has been assigned a new value (with the abstract value {@code val}). This includes the
* following steps (assume that {@code arrayAccess} is of the form <em>a[i]</em> for some
* <em>a</em>.
*
* <ol>
* <li value="1">Remove any abstract value for other array access <em>b[j]</em> where <em>a</em>
* and <em>b</em> can be aliases, or where either <em>b</em> or <em>j</em> contains a
* modifiable alias of <em>a[i]</em>.
* <li value="2">Remove any abstract values for field accesses <em>b.g</em> where <em>a[i]</em>
* might alias any expression in the receiver <em>b</em> and there is an array expression
* somewhere in the receiver.
* <li value="3">Remove any information about method calls.
* </ol>
*
* @param val the abstract value of the value assigned to {@code n} (or {@code null} if the
* abstract value is not known).
*/
protected void removeConflicting(ArrayAccess arrayAccess, @Nullable V val) {
final Iterator<Map.Entry<ArrayAccess, V>> arrayValuesIterator = arrayValues.entrySet().iterator();
while (arrayValuesIterator.hasNext()) {
Map.Entry<ArrayAccess, V> entry = arrayValuesIterator.next();
ArrayAccess otherArrayAccess = entry.getKey();
// case 1:
if (otherArrayAccess.containsModifiableAliasOf(this, arrayAccess)) {
// remove information completely
arrayValuesIterator.remove();
} else if (canAlias(arrayAccess.getArray(), otherArrayAccess.getArray())) {
// TODO: one could be less strict here, and only raise the abstract
// value for all array expressions with potentially aliasing receivers.
// remove information completely
arrayValuesIterator.remove();
}
}
// case 2:
final Iterator<Map.Entry<FieldAccess, V>> fieldValuesIterator = fieldValues.entrySet().iterator();
while (fieldValuesIterator.hasNext()) {
Map.Entry<FieldAccess, V> entry = fieldValuesIterator.next();
FieldAccess otherFieldAccess = entry.getKey();
JavaExpression otherReceiver = otherFieldAccess.getReceiver();
if (otherReceiver.containsModifiableAliasOf(this, arrayAccess) && otherReceiver.containsOfClass(ArrayAccess.class)) {
// remove information completely
fieldValuesIterator.remove();
}
}
// case 3:
methodValues.clear();
}
Aggregations