Search in sources :

Example 1 with ArrayAccess

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);
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) ArrayAccess(org.checkerframework.dataflow.expression.ArrayAccess) JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) ArrayLen(org.checkerframework.common.value.qual.ArrayLen) JavaExpressionParseException(org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException) ArrayCreation(org.checkerframework.dataflow.expression.ArrayCreation) ArrayLenRange(org.checkerframework.common.value.qual.ArrayLenRange) ValueLiteral(org.checkerframework.dataflow.expression.ValueLiteral) StringVal(org.checkerframework.common.value.qual.StringVal)

Example 2 with ArrayAccess

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.
    }
}
Also used : CFValue(org.checkerframework.framework.flow.CFValue) ArrayAccess(org.checkerframework.dataflow.expression.ArrayAccess) LocalVariable(org.checkerframework.dataflow.expression.LocalVariable) ClassName(org.checkerframework.dataflow.expression.ClassName) FieldAccess(org.checkerframework.dataflow.expression.FieldAccess) ThisReference(org.checkerframework.dataflow.expression.ThisReference) MethodCall(org.checkerframework.dataflow.expression.MethodCall)

Example 3 with ArrayAccess

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.
    }
}
Also used : ArrayAccess(org.checkerframework.dataflow.expression.ArrayAccess) LocalVariable(org.checkerframework.dataflow.expression.LocalVariable) ClassName(org.checkerframework.dataflow.expression.ClassName) FieldAccess(org.checkerframework.dataflow.expression.FieldAccess) ThisReference(org.checkerframework.dataflow.expression.ThisReference) MethodCall(org.checkerframework.dataflow.expression.MethodCall)

Example 4 with ArrayAccess

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();
}
Also used : ArrayAccess(org.checkerframework.dataflow.expression.ArrayAccess) FieldAccess(org.checkerframework.dataflow.expression.FieldAccess) HashMap(java.util.HashMap) Map(java.util.Map)

Example 5 with ArrayAccess

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();
}
Also used : ArrayAccess(org.checkerframework.dataflow.expression.ArrayAccess) JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) FieldAccess(org.checkerframework.dataflow.expression.FieldAccess) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

ArrayAccess (org.checkerframework.dataflow.expression.ArrayAccess)9 FieldAccess (org.checkerframework.dataflow.expression.FieldAccess)8 MethodCall (org.checkerframework.dataflow.expression.MethodCall)6 HashMap (java.util.HashMap)5 Map (java.util.Map)5 ClassName (org.checkerframework.dataflow.expression.ClassName)5 LocalVariable (org.checkerframework.dataflow.expression.LocalVariable)5 JavaExpression (org.checkerframework.dataflow.expression.JavaExpression)2 ThisReference (org.checkerframework.dataflow.expression.ThisReference)2 AnnotationMirror (javax.lang.model.element.AnnotationMirror)1 ArrayLen (org.checkerframework.common.value.qual.ArrayLen)1 ArrayLenRange (org.checkerframework.common.value.qual.ArrayLenRange)1 StringVal (org.checkerframework.common.value.qual.StringVal)1 ArrayCreation (org.checkerframework.dataflow.expression.ArrayCreation)1 ValueLiteral (org.checkerframework.dataflow.expression.ValueLiteral)1 CFValue (org.checkerframework.framework.flow.CFValue)1 JavaExpressionParseException (org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException)1