Search in sources :

Example 51 with JavaExpression

use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.

the class BaseTypeVisitor method checkContractsSubset.

/**
 * Checks that {@code mustSubset} is a subset of {@code set} in the following sense: For every
 * expression in {@code mustSubset} there must be the same expression in {@code set}, with the
 * same (or a stronger) annotation.
 *
 * <p>This uses field {@link #methodTree} to determine where to issue an error message.
 *
 * @param overriderType the subtype
 * @param overriddenType the supertype
 * @param mustSubset annotations that should be weaker
 * @param set anontations that should be stronger
 * @param messageKey message key for error messages
 */
private void checkContractsSubset(AnnotatedTypeMirror overriderType, AnnotatedDeclaredType overriddenType, Set<Pair<JavaExpression, AnnotationMirror>> mustSubset, Set<Pair<JavaExpression, AnnotationMirror>> set, @CompilerMessageKey String messageKey) {
    for (Pair<JavaExpression, AnnotationMirror> weak : mustSubset) {
        boolean found = false;
        for (Pair<JavaExpression, AnnotationMirror> strong : set) {
            // are we looking at a contract of the same receiver?
            if (weak.first.equals(strong.first)) {
                // check subtyping relationship of annotations
                QualifierHierarchy qualifierHierarchy = atypeFactory.getQualifierHierarchy();
                if (qualifierHierarchy.isSubtype(strong.second, weak.second)) {
                    found = true;
                    break;
                }
            }
        }
        if (!found) {
            String overriddenTypeString = overriddenType.getUnderlyingType().asElement().toString();
            String overriderTypeString;
            if (overriderType.getKind() == TypeKind.DECLARED) {
                DeclaredType overriderTypeMirror = ((AnnotatedDeclaredType) overriderType).getUnderlyingType();
                overriderTypeString = overriderTypeMirror.asElement().toString();
            } else {
                overriderTypeString = overriderType.toString();
            }
            // weak.second is the AnnotationMirror that is too strong.  It might be from the
            // precondition or the postcondition.
            // These are the annotations that are too weak.
            StringJoiner strongRelevantAnnos = new StringJoiner(" ").setEmptyValue("no information");
            for (Pair<JavaExpression, AnnotationMirror> strong : set) {
                if (weak.first.equals(strong.first)) {
                    strongRelevantAnnos.add(strong.second.toString());
                }
            }
            Object overriddenAnno;
            Object overriderAnno;
            if (messageKey.contains(".precondition.")) {
                overriddenAnno = strongRelevantAnnos;
                overriderAnno = weak.second;
            } else {
                overriddenAnno = weak.second;
                overriderAnno = strongRelevantAnnos;
            }
            checker.reportError(methodTree, messageKey, weak.first, methodTree.getName(), overriddenTypeString, overriddenAnno, overriderTypeString, overriderAnno);
        }
    }
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) StringToJavaExpression(org.checkerframework.framework.util.StringToJavaExpression) JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) QualifierHierarchy(org.checkerframework.framework.type.QualifierHierarchy) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) StringJoiner(java.util.StringJoiner) DeclaredType(javax.lang.model.type.DeclaredType) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType)

Example 52 with JavaExpression

use of org.checkerframework.dataflow.expression.JavaExpression 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)

Example 53 with JavaExpression

use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.

the class MustCallConsistencyAnalyzer method checkCreatesMustCallForInvocation.

/**
 * Checks that an invocation of a CreatesMustCallFor method is valid.
 *
 * <p>Such an invocation is valid if any of the conditions in {@link
 * #isValidCreatesMustCallForExpression(Set, JavaExpression, TreePath)} is true. If none of these
 * conditions are true, this method issues a reset.not.owning error.
 *
 * <p>For soundness, this method also guarantees that if any of the expressions in the
 * CreatesMustCallFor annotation has a tracked Obligation, any tracked resource aliases of it will
 * be removed (lest the analysis conclude that it is already closed because one of these aliases
 * was closed before the method was invoked). Aliases created after the CreatesMustCallFor method
 * is invoked are still permitted.
 *
 * @param obligations the currently-tracked Obligations; this value is side-effected if there is
 *     an Obligation in it which tracks any expression from the CreatesMustCallFor annotation as
 *     one of its resource aliases
 * @param node a method invocation node, invoking a method with a CreatesMustCallFor annotation
 */
private void checkCreatesMustCallForInvocation(Set<Obligation> obligations, MethodInvocationNode node) {
    TreePath currentPath = typeFactory.getPath(node.getTree());
    List<JavaExpression> cmcfExpressions = CreatesMustCallForElementSupplier.getCreatesMustCallForExpressions(node, typeFactory, typeFactory);
    List<JavaExpression> missing = new ArrayList<>(0);
    for (JavaExpression expression : cmcfExpressions) {
        if (!isValidCreatesMustCallForExpression(obligations, expression, currentPath)) {
            missing.add(expression);
        }
    }
    if (missing.isEmpty()) {
        // All expressions matched one of the rules, so the invocation is valid.
        return;
    }
    String missingStrs = StringsPlume.join(", ", missing);
    checker.reportError(node.getTree(), "reset.not.owning", node.getTarget().getMethod().getSimpleName().toString(), missingStrs);
}
Also used : JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) StringToJavaExpression(org.checkerframework.framework.util.StringToJavaExpression) TreePath(com.sun.source.util.TreePath) ArrayList(java.util.ArrayList)

Example 54 with JavaExpression

use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.

the class MustCallConsistencyAnalyzer method isValidCreatesMustCallForExpression.

/**
 * Checks the validity of the given expression from an invoked method's {@link
 * org.checkerframework.checker.mustcall.qual.CreatesMustCallFor} annotation. Helper method for
 * {@link #checkCreatesMustCallForInvocation(Set, MethodInvocationNode)}.
 *
 * <p>An expression is valid if one of the following conditions is true: 1) the expression is an
 * owning pointer, 2) the expression already has a tracked Obligation (i.e. there is already a
 * resource alias in some Obligation's resource alias set that refers to the expression), or 3)
 * the method in which the invocation occurs also has an @CreatesMustCallFor annotation, with the
 * same expression.
 *
 * @param obligations the currently-tracked Obligations; this value is side-effected if there is
 *     an Obligation in it which tracks {@code expression} as one of its resource aliases
 * @param expression an element of a method's @CreatesMustCallFor annotation
 * @param path the path to the invocation of the method from whose @CreateMustCallFor annotation
 *     {@code expression} came
 * @return true iff the expression is valid, as defined above
 */
private boolean isValidCreatesMustCallForExpression(Set<Obligation> obligations, JavaExpression expression, TreePath path) {
    if (expression instanceof FieldAccess) {
        Element elt = ((FieldAccess) expression).getField();
        if (!checker.hasOption(MustCallChecker.NO_LIGHTWEIGHT_OWNERSHIP) && typeFactory.getDeclAnnotation(elt, Owning.class) != null) {
            // The expression is an Owning field.  This satisfies case 1.
            return true;
        }
    } else if (expression instanceof LocalVariable) {
        Element elt = ((LocalVariable) expression).getElement();
        if (!checker.hasOption(MustCallChecker.NO_LIGHTWEIGHT_OWNERSHIP) && typeFactory.getDeclAnnotation(elt, Owning.class) != null) {
            // This satisfies case 1.
            return true;
        } else {
            Obligation toRemove = null;
            Obligation toAdd = null;
            for (Obligation obligation : obligations) {
                ResourceAlias alias = obligation.getResourceAlias(expression);
                if (alias != null) {
                    // This satisfies case 2 above. Remove all its aliases, then return below.
                    if (toRemove != null) {
                        throw new TypeSystemError("tried to remove multiple sets containing a reset expression at once");
                    }
                    toRemove = obligation;
                    toAdd = new Obligation(ImmutableSet.of(alias));
                }
            }
            if (toRemove != null) {
                obligations.remove(toRemove);
                obligations.add(toAdd);
                // This satisfies case 2.
                return true;
            }
        }
    }
    // TODO: Getting this every time is inefficient if a method has many @CreatesMustCallFor
    // annotations, but that should be rare.
    MethodTree enclosingMethodTree = TreePathUtil.enclosingMethod(path);
    if (enclosingMethodTree == null) {
        return false;
    }
    ExecutableElement enclosingMethodElt = TreeUtils.elementFromDeclaration(enclosingMethodTree);
    MustCallAnnotatedTypeFactory mcAtf = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
    List<String> enclosingCmcfValues = ResourceLeakVisitor.getCreatesMustCallForValues(enclosingMethodElt, mcAtf, typeFactory);
    if (enclosingCmcfValues.isEmpty()) {
        return false;
    }
    for (String enclosingCmcfValue : enclosingCmcfValues) {
        JavaExpression enclosingTarget;
        try {
            enclosingTarget = StringToJavaExpression.atMethodBody(enclosingCmcfValue, enclosingMethodTree, checker);
        } catch (JavaExpressionParseException e) {
            // Do not issue an error here, because it would be a duplicate.
            // The error will be issued by the Transfer class of the checker,
            // via the CreatesMustCallForElementSupplier interface.
            enclosingTarget = null;
        }
        if (areSame(expression, enclosingTarget)) {
            // This satisfies case 3.
            return true;
        }
    }
    return false;
}
Also used : JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) StringToJavaExpression(org.checkerframework.framework.util.StringToJavaExpression) MethodTree(com.sun.source.tree.MethodTree) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) LocalVariable(org.checkerframework.dataflow.expression.LocalVariable) TypeSystemError(org.checkerframework.javacutil.TypeSystemError) MustCallAnnotatedTypeFactory(org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory) NotOwning(org.checkerframework.checker.mustcall.qual.NotOwning) Owning(org.checkerframework.checker.mustcall.qual.Owning) JavaExpressionParseException(org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException) FieldAccess(org.checkerframework.dataflow.expression.FieldAccess)

Example 55 with JavaExpression

use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.

the class ResourceLeakTransfer method handleCreatesMustCallFor.

/**
 * Clears the called-methods store of all information about the target if an @CreatesMustCallFor
 * method is invoked and the type factory can create obligations. Otherwise, does nothing.
 *
 * @param n a method invocation
 * @param result the transfer result whose stores should be cleared of information
 */
private void handleCreatesMustCallFor(MethodInvocationNode n, TransferResult<CFValue, CFStore> result) {
    if (!rlTypeFactory.canCreateObligations()) {
        return;
    }
    List<JavaExpression> targetExprs = CreatesMustCallForElementSupplier.getCreatesMustCallForExpressions(n, rlTypeFactory, rlTypeFactory);
    AnnotationMirror defaultType = rlTypeFactory.top;
    for (JavaExpression targetExpr : targetExprs) {
        CFValue defaultTypeValue = analysis.createSingleAnnotationValue(defaultType, targetExpr.getType());
        if (result.containsTwoStores()) {
            result.getThenStore().replaceValue(targetExpr, defaultTypeValue);
            result.getElseStore().replaceValue(targetExpr, defaultTypeValue);
        } else {
            result.getRegularStore().replaceValue(targetExpr, defaultTypeValue);
        }
    }
}
Also used : CFValue(org.checkerframework.framework.flow.CFValue) AnnotationMirror(javax.lang.model.element.AnnotationMirror) JavaExpression(org.checkerframework.dataflow.expression.JavaExpression)

Aggregations

JavaExpression (org.checkerframework.dataflow.expression.JavaExpression)87 AnnotationMirror (javax.lang.model.element.AnnotationMirror)39 Node (org.checkerframework.dataflow.cfg.node.Node)23 StringToJavaExpression (org.checkerframework.framework.util.StringToJavaExpression)21 CFValue (org.checkerframework.framework.flow.CFValue)20 ExecutableElement (javax.lang.model.element.ExecutableElement)19 MethodInvocationNode (org.checkerframework.dataflow.cfg.node.MethodInvocationNode)19 ArrayList (java.util.ArrayList)15 CFStore (org.checkerframework.framework.flow.CFStore)15 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)13 JavaExpressionParseException (org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException)13 Tree (com.sun.source.tree.Tree)12 List (java.util.List)11 FieldAccess (org.checkerframework.dataflow.expression.FieldAccess)11 MethodTree (com.sun.source.tree.MethodTree)10 TreePath (com.sun.source.util.TreePath)10 HashMap (java.util.HashMap)10 Map (java.util.Map)9 Element (javax.lang.model.element.Element)9 VariableElement (javax.lang.model.element.VariableElement)9