Search in sources :

Example 31 with Receiver

use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver 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(FlowExpressions.ArrayAccess arrayAccess, @Nullable V val) {
    Map<FlowExpressions.ArrayAccess, V> newArrayValues = new HashMap<>();
    for (Entry<FlowExpressions.ArrayAccess, V> e : arrayValues.entrySet()) {
        FlowExpressions.ArrayAccess otherArrayAccess = e.getKey();
        V otherVal = e.getValue();
        // case 1:
        if (otherArrayAccess.containsModifiableAliasOf(this, arrayAccess)) {
            // remove information completely
            continue;
        }
        if (canAlias(arrayAccess.getReceiver(), otherArrayAccess.getReceiver())) {
            // remove information completely
            continue;
        }
        // information is save to be carried over
        newArrayValues.put(otherArrayAccess, otherVal);
    }
    arrayValues = newArrayValues;
    // case 2:
    Map<FlowExpressions.FieldAccess, V> newFieldValues = new HashMap<>();
    for (Entry<FieldAccess, V> e : fieldValues.entrySet()) {
        FlowExpressions.FieldAccess otherFieldAccess = e.getKey();
        V otherVal = e.getValue();
        Receiver receiver = otherFieldAccess.getReceiver();
        if (receiver.containsModifiableAliasOf(this, arrayAccess) && receiver.containsOfClass(ArrayAccess.class)) {
            // remove information completely
            continue;
        }
        newFieldValues.put(otherFieldAccess, otherVal);
    }
    fieldValues = newFieldValues;
    // case 3:
    methodValues = new HashMap<>();
}
Also used : HashMap(java.util.HashMap) ArrayAccess(org.checkerframework.dataflow.analysis.FlowExpressions.ArrayAccess) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver) FieldAccess(org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess) ArrayAccess(org.checkerframework.dataflow.analysis.FlowExpressions.ArrayAccess) FlowExpressions(org.checkerframework.dataflow.analysis.FlowExpressions) FieldAccess(org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess)

Example 32 with Receiver

use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver in project checker-framework by typetools.

the class CFAbstractStore method updateForMethodCall.

/* --------------------------------------------------------- */
/* Handling of fields */
/* --------------------------------------------------------- */
/**
 * Remove any information that might not be valid any more after a method call, and add
 * information guaranteed by the method.
 *
 * <ol>
 *   <li>If the method is side-effect-free (as indicated by {@link
 *       org.checkerframework.dataflow.qual.SideEffectFree} or {@link
 *       org.checkerframework.dataflow.qual.Pure}), then no information needs to be removed.
 *   <li>Otherwise, all information about field accesses {@code a.f} needs to be removed, except
 *       if the method {@code n} cannot modify {@code a.f} (e.g., if {@code a} is a local
 *       variable or {@code this}, and {@code f} is final).
 *   <li>Furthermore, if the field has a monotonic annotation, then its information can also be
 *       kept.
 * </ol>
 *
 * Furthermore, if the method is deterministic, we store its result {@code val} in the store.
 */
public void updateForMethodCall(MethodInvocationNode n, AnnotatedTypeFactory atypeFactory, V val) {
    ExecutableElement method = n.getTarget().getMethod();
    // case 1: remove information if necessary
    if (!(analysis.checker.hasOption("assumeSideEffectFree") || isSideEffectFree(atypeFactory, method))) {
        // update field values
        Map<FlowExpressions.FieldAccess, V> newFieldValues = new HashMap<>();
        for (Entry<FlowExpressions.FieldAccess, V> e : fieldValues.entrySet()) {
            FlowExpressions.FieldAccess fieldAccess = e.getKey();
            V otherVal = e.getValue();
            // case 3:
            List<Pair<AnnotationMirror, AnnotationMirror>> fieldAnnotations = atypeFactory.getAnnotationWithMetaAnnotation(fieldAccess.getField(), MonotonicQualifier.class);
            V newOtherVal = null;
            for (Pair<AnnotationMirror, AnnotationMirror> fieldAnnotation : fieldAnnotations) {
                AnnotationMirror monotonicAnnotation = fieldAnnotation.second;
                Name annotation = AnnotationUtils.getElementValueClassName(monotonicAnnotation, "value", false);
                AnnotationMirror target = AnnotationBuilder.fromName(atypeFactory.getElementUtils(), annotation);
                // Make sure the 'target' annotation is present.
                if (AnnotationUtils.containsSame(otherVal.getAnnotations(), target)) {
                    newOtherVal = analysis.createSingleAnnotationValue(target, otherVal.getUnderlyingType()).mostSpecific(newOtherVal, null);
                }
            }
            if (newOtherVal != null) {
                // keep information for all hierarchies where we had a
                // monotone annotation.
                newFieldValues.put(fieldAccess, newOtherVal);
                continue;
            }
            // case 2:
            if (!fieldAccess.isUnmodifiableByOtherCode()) {
                // remove information completely
                continue;
            }
            // keep information
            newFieldValues.put(fieldAccess, otherVal);
        }
        fieldValues = newFieldValues;
        // update method values
        methodValues.clear();
        arrayValues.clear();
    }
    // store information about method call if possible
    Receiver methodCall = FlowExpressions.internalReprOf(analysis.getTypeFactory(), n);
    replaceValue(methodCall, val);
}
Also used : HashMap(java.util.HashMap) ExecutableElement(javax.lang.model.element.ExecutableElement) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver) Name(javax.lang.model.element.Name) ClassName(org.checkerframework.dataflow.analysis.FlowExpressions.ClassName) FieldAccess(org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess) AnnotationMirror(javax.lang.model.element.AnnotationMirror) FlowExpressions(org.checkerframework.dataflow.analysis.FlowExpressions) FieldAccess(org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess) Pair(org.checkerframework.javacutil.Pair)

Example 33 with Receiver

use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver in project checker-framework by typetools.

the class FlowExpressionParseUtil method parseMemberSelect.

private static Receiver parseMemberSelect(String s, ProcessingEnvironment env, FlowExpressionContext context, TreePath path) throws FlowExpressionParseException {
    Pair<String, String> select = parseMemberSelect(s);
    assert select != null : "isMemberSelect must be called first";
    Receiver receiver;
    String memberSelected;
    Resolver resolver = new Resolver(env);
    // Attempt to match a package and class name first.
    Pair<ClassName, String> classAndRemainingString = matchPackageAndClassNameWithinExpression(s, resolver, path);
    if (classAndRemainingString != null) {
        receiver = classAndRemainingString.first;
        memberSelected = classAndRemainingString.second;
        if (memberSelected == null) {
            throw constructParserException(s, "a class cannot terminate a flow expression string");
        }
    } else {
        String receiverString = select.first;
        memberSelected = select.second;
        receiver = parseHelper(receiverString, context, path);
    }
    if (memberSelected.equals("class")) {
        if (receiver instanceof FlowExpressions.ClassName && !context.parsingMember) {
            return receiver;
        } else {
            throw constructParserException(s, "class is not a legal identifier");
        }
    }
    // Parse the rest, with a new receiver.
    FlowExpressionContext newContext = context.copyChangeToParsingMemberOfReceiver(receiver);
    return parseHelper(memberSelected, newContext, path);
}
Also used : ClassName(org.checkerframework.dataflow.analysis.FlowExpressions.ClassName) Resolver(org.checkerframework.javacutil.Resolver) ClassName(org.checkerframework.dataflow.analysis.FlowExpressions.ClassName) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver) FlowExpressions(org.checkerframework.dataflow.analysis.FlowExpressions)

Example 34 with Receiver

use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver in project checker-framework by typetools.

the class FlowExpressionParseUtil method parseMethod.

private static Receiver parseMethod(String s, FlowExpressionContext context, TreePath path, ProcessingEnvironment env) throws FlowExpressionParseException {
    Pair<Pair<String, String>, String> method = parseMethod(s);
    if (method == null) {
        return null;
    }
    String methodName = method.first.first;
    // parse parameter list
    String parameterList = method.first.second;
    List<Receiver> parameters = ParameterListParser.parseParameterList(parameterList, true, context.copyAndUseOuterReceiver(), path);
    // get types for parameters
    List<TypeMirror> parameterTypes = new ArrayList<>();
    for (Receiver p : parameters) {
        parameterTypes.add(p.getType());
    }
    ExecutableElement methodElement = null;
    try {
        Element element = null;
        // try to find the correct method
        Resolver resolver = new Resolver(env);
        TypeMirror receiverType = context.receiver.getType();
        if (receiverType.getKind() == TypeKind.ARRAY) {
            element = resolver.findMethod(methodName, receiverType, path, parameterTypes);
        }
        // Search for method in each enclosing class.
        while (receiverType.getKind() == TypeKind.DECLARED) {
            element = resolver.findMethod(methodName, receiverType, path, parameterTypes);
            if (element.getKind() == ElementKind.METHOD) {
                break;
            }
            receiverType = getTypeOfEnclosingClass((DeclaredType) receiverType);
        }
        if (element == null) {
            throw constructParserException(s, "element==null");
        }
        if (element.getKind() != ElementKind.METHOD) {
            throw constructParserException(s, "element.getKind()==" + element.getKind());
        }
        methodElement = (ExecutableElement) element;
        for (int i = 0; i < parameters.size(); i++) {
            VariableElement formal = methodElement.getParameters().get(i);
            TypeMirror formalType = formal.asType();
            Receiver actual = parameters.get(i);
            TypeMirror actualType = actual.getType();
            // boxing necessary
            if (TypesUtils.isBoxedPrimitive(formalType) && TypesUtils.isPrimitive(actualType)) {
                MethodSymbol valueOfMethod = TreeBuilder.getValueOfMethod(env, formalType);
                List<Receiver> p = new ArrayList<>();
                p.add(actual);
                Receiver boxedParam = new MethodCall(formalType, valueOfMethod, new ClassName(formalType), p);
                parameters.set(i, boxedParam);
            }
        }
    } catch (Throwable t) {
        throw constructParserException(s, t);
    }
    assert methodElement != null;
    /*if (!PurityUtils.isDeterministic(context.checkerContext.getAnnotationProvider(),
                methodElement)) {
            throw new FlowExpressionParseException(Result.failure(
                    "flowexpr.method.not.deterministic",
                    methodElement.getSimpleName()));
        }*/
    if (ElementUtils.isStatic(methodElement)) {
        Element classElem = methodElement.getEnclosingElement();
        Receiver staticClassReceiver = new ClassName(ElementUtils.getType(classElem));
        return new MethodCall(ElementUtils.getType(methodElement), methodElement, staticClassReceiver, parameters);
    } else {
        if (context.receiver instanceof ClassName) {
            throw constructParserException(s, "a non-static method call cannot have a class name as a receiver.");
        }
        TypeMirror methodType = TypesUtils.substituteMethodReturnType(methodElement, context.receiver.getType(), env);
        return new MethodCall(methodType, methodElement, context.receiver, parameters);
    }
}
Also used : Resolver(org.checkerframework.javacutil.Resolver) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver) VariableElement(javax.lang.model.element.VariableElement) MethodCall(org.checkerframework.dataflow.analysis.FlowExpressions.MethodCall) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) TypeMirror(javax.lang.model.type.TypeMirror) ClassName(org.checkerframework.dataflow.analysis.FlowExpressions.ClassName) Pair(org.checkerframework.javacutil.Pair) DeclaredType(javax.lang.model.type.DeclaredType)

Example 35 with Receiver

use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver in project checker-framework by typetools.

the class FlowExpressionParseUtil method internalReprOfVariable.

public static Receiver internalReprOfVariable(AnnotatedTypeFactory provider, VariableTree tree) throws FlowExpressionParseException {
    Element elt = TreeUtils.elementFromDeclaration(tree);
    if (elt.getKind() == ElementKind.LOCAL_VARIABLE || elt.getKind() == ElementKind.RESOURCE_VARIABLE || elt.getKind() == ElementKind.EXCEPTION_PARAMETER || elt.getKind() == ElementKind.PARAMETER) {
        return new LocalVariable(elt);
    }
    Receiver receiverF = FlowExpressions.internalReprOfImplicitReceiver(elt);
    FlowExpressionParseUtil.FlowExpressionContext context = new FlowExpressionParseUtil.FlowExpressionContext(receiverF, null, provider.getContext());
    return FlowExpressionParseUtil.parse(tree.getName().toString(), context, provider.getPath(tree), false);
}
Also used : TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) LocalVariable(org.checkerframework.dataflow.analysis.FlowExpressions.LocalVariable) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver)

Aggregations

Receiver (org.checkerframework.dataflow.analysis.FlowExpressions.Receiver)55 AnnotationMirror (javax.lang.model.element.AnnotationMirror)19 Node (org.checkerframework.dataflow.cfg.node.Node)15 MethodInvocationNode (org.checkerframework.dataflow.cfg.node.MethodInvocationNode)14 FieldAccessNode (org.checkerframework.dataflow.cfg.node.FieldAccessNode)10 CFValue (org.checkerframework.framework.flow.CFValue)9 FlowExpressions (org.checkerframework.dataflow.analysis.FlowExpressions)8 FieldAccess (org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess)8 NumericalAdditionNode (org.checkerframework.dataflow.cfg.node.NumericalAdditionNode)8 NumericalSubtractionNode (org.checkerframework.dataflow.cfg.node.NumericalSubtractionNode)8 ArrayList (java.util.ArrayList)7 TypeMirror (javax.lang.model.type.TypeMirror)7 ClassName (org.checkerframework.dataflow.analysis.FlowExpressions.ClassName)7 AssignmentNode (org.checkerframework.dataflow.cfg.node.AssignmentNode)7 Tree (com.sun.source.tree.Tree)6 TreePath (com.sun.source.util.TreePath)6 ArrayCreationNode (org.checkerframework.dataflow.cfg.node.ArrayCreationNode)6 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)6 MethodTree (com.sun.source.tree.MethodTree)5 CaseNode (org.checkerframework.dataflow.cfg.node.CaseNode)5