Search in sources :

Example 1 with TypeSystemError

use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.

the class MustCallConsistencyAnalyzer method checkReassignmentToField.

/**
 * Issues an error if the given re-assignment to a non-final, owning field is not valid. A
 * re-assignment is valid if the called methods type of the lhs before the assignment satisfies
 * the must-call obligations of the field.
 *
 * @param obligations current tracked Obligations
 * @param node an assignment to a non-final, owning field
 */
private void checkReassignmentToField(Set<Obligation> obligations, AssignmentNode node) {
    Node lhsNode = node.getTarget();
    if (!(lhsNode instanceof FieldAccessNode)) {
        throw new TypeSystemError("checkReassignmentToField: non-field node " + node + " of class " + node.getClass());
    }
    FieldAccessNode lhs = (FieldAccessNode) lhsNode;
    Node receiver = lhs.getReceiver();
    // TODO: it would be better to defer getting the path until after checking
    // for a CreatesMustCallFor annotation, because getting the path can be expensive.
    // It might be possible to exploit the CFG structure to find the containing
    // method (rather than using the path, as below), because if a method is being
    // analyzed then it should be the root of the CFG (I think).
    TreePath currentPath = typeFactory.getPath(node.getTree());
    MethodTree enclosingMethodTree = TreePathUtil.enclosingMethod(currentPath);
    if (enclosingMethodTree == null) {
        // also a declaration must be a field initializer.
        if (node.getTree().getKind() == Tree.Kind.VARIABLE) {
            return;
        } else {
            // Issue an error if the field has a non-empty must-call type.
            MustCallAnnotatedTypeFactory mcTypeFactory = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
            AnnotationMirror mcAnno = mcTypeFactory.getAnnotatedType(lhs.getElement()).getAnnotation(MustCall.class);
            List<String> mcValues = AnnotationUtils.getElementValueArray(mcAnno, mcTypeFactory.getMustCallValueElement(), String.class);
            if (mcValues.isEmpty()) {
                return;
            }
            Element lhsElement = TreeUtils.elementFromTree(lhs.getTree());
            checker.reportError(node.getTree(), "required.method.not.called", formatMissingMustCallMethods(mcValues), "field " + lhsElement.getSimpleName().toString(), lhsElement.asType().toString(), "Field assignment outside method or declaration might overwrite field's current value");
            return;
        }
    }
    // on the method declaration), or 2) the rhs is a null literal (so there's nothing to reset).
    if (!(receiver instanceof LocalVariableNode && varTrackedInObligations(obligations, (LocalVariableNode) receiver)) && !(node.getExpression() instanceof NullLiteralNode)) {
        checkEnclosingMethodIsCreatesMustCallFor(node, enclosingMethodTree);
    }
    MustCallAnnotatedTypeFactory mcTypeFactory = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
    // Get the Must Call type for the field. If there's info about this field in the store, use
    // that. Otherwise, use the declared type of the field
    CFStore mcStore = mcTypeFactory.getStoreBefore(lhs);
    CFValue mcValue = mcStore.getValue(lhs);
    AnnotationMirror mcAnno;
    if (mcValue == null) {
        // No store value, so use the declared type.
        mcAnno = mcTypeFactory.getAnnotatedType(lhs.getElement()).getAnnotation(MustCall.class);
    } else {
        mcAnno = AnnotationUtils.getAnnotationByClass(mcValue.getAnnotations(), MustCall.class);
    }
    List<String> mcValues = AnnotationUtils.getElementValueArray(mcAnno, mcTypeFactory.getMustCallValueElement(), String.class);
    if (mcValues.isEmpty()) {
        return;
    }
    // Get the store before the RHS rather than the assignment node, because the CFG always has
    // the RHS first. If the RHS has side-effects, then the assignment node's store will have
    // had its inferred types erased.
    Node rhs = node.getExpression();
    CFStore cmStoreBefore = typeFactory.getStoreBefore(rhs);
    CFValue cmValue = cmStoreBefore == null ? null : cmStoreBefore.getValue(lhs);
    AnnotationMirror cmAnno = null;
    if (cmValue != null) {
        for (AnnotationMirror anno : cmValue.getAnnotations()) {
            if (AnnotationUtils.areSameByName(anno, "org.checkerframework.checker.calledmethods.qual.CalledMethods")) {
                cmAnno = anno;
                break;
            }
        }
    }
    if (cmAnno == null) {
        cmAnno = typeFactory.top;
    }
    if (!calledMethodsSatisfyMustCall(mcValues, cmAnno)) {
        Element lhsElement = TreeUtils.elementFromTree(lhs.getTree());
        if (!checker.shouldSkipUses(lhsElement)) {
            checker.reportError(node.getTree(), "required.method.not.called", formatMissingMustCallMethods(mcValues), "field " + lhsElement.getSimpleName().toString(), lhsElement.asType().toString(), " Non-final owning field might be overwritten");
        }
    }
}
Also used : CFStore(org.checkerframework.framework.flow.CFStore) MethodTree(com.sun.source.tree.MethodTree) TypeCastNode(org.checkerframework.dataflow.cfg.node.TypeCastNode) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) ThisNode(org.checkerframework.dataflow.cfg.node.ThisNode) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) NullLiteralNode(org.checkerframework.dataflow.cfg.node.NullLiteralNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) ReturnNode(org.checkerframework.dataflow.cfg.node.ReturnNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) Node(org.checkerframework.dataflow.cfg.node.Node) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeSystemError(org.checkerframework.javacutil.TypeSystemError) MustCallAnnotatedTypeFactory(org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) CFValue(org.checkerframework.framework.flow.CFValue) AnnotationMirror(javax.lang.model.element.AnnotationMirror) TreePath(com.sun.source.util.TreePath) MustCall(org.checkerframework.checker.mustcall.qual.MustCall) NullLiteralNode(org.checkerframework.dataflow.cfg.node.NullLiteralNode)

Example 2 with TypeSystemError

use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.

the class MustCallAnnotatedTypeFactory method methodFromUsePreSubstitution.

/**
 * Treat non-owning method parameters as @MustCallUnknown (top) when the method is called.
 */
@Override
public void methodFromUsePreSubstitution(ExpressionTree tree, AnnotatedExecutableType type) {
    ExecutableElement declaration;
    if (tree instanceof MethodInvocationTree) {
        declaration = TreeUtils.elementFromUse((MethodInvocationTree) tree);
    } else if (tree instanceof MemberReferenceTree) {
        declaration = (ExecutableElement) TreeUtils.elementFromTree(tree);
    } else {
        throw new TypeSystemError("unexpected type of method tree: " + tree.getKind());
    }
    changeNonOwningParameterTypesToTop(declaration, type);
    super.methodFromUsePreSubstitution(tree, type);
}
Also used : MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExecutableElement(javax.lang.model.element.ExecutableElement) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) TypeSystemError(org.checkerframework.javacutil.TypeSystemError)

Example 3 with TypeSystemError

use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.

the class DefaultQualifierKindHierarchy method createDirectSuperMap.

/**
 * Creates a mapping from a {@link QualifierKind} to a set of its direct super qualifier kinds.
 * The direct super qualifier kinds do not contain the qualifier itself. This mapping is used to
 * create the bottom set, to create the top set, and by {@link
 * #initializeQualifierKindFields(Map)}.
 *
 * <p>This implementation uses the {@link SubtypeOf} meta-annotation. Subclasses may override this
 * method to create the direct super map some other way.
 *
 * <p>Note that this method is called from the constructor when {@link #nameToQualifierKind} and
 * {@link #qualifierKinds} are the only fields that have nonnull values. This method is not
 * static, so it can be overridden by subclasses.
 *
 * @return a mapping from each {@link QualifierKind} to a set of its direct super qualifiers
 */
@RequiresNonNull({ "this.nameToQualifierKind", "this.qualifierKinds" })
protected Map<DefaultQualifierKind, Set<DefaultQualifierKind>> createDirectSuperMap(@UnderInitialization DefaultQualifierKindHierarchy this, ) {
    Map<DefaultQualifierKind, Set<DefaultQualifierKind>> directSuperMap = new TreeMap<>();
    for (DefaultQualifierKind qualifierKind : qualifierKinds) {
        SubtypeOf subtypeOfMetaAnno = qualifierKind.getAnnotationClass().getAnnotation(SubtypeOf.class);
        if (subtypeOfMetaAnno == null) {
            // qualifierKind has no @SubtypeOf: it must be top or polymorphic
            continue;
        }
        Set<DefaultQualifierKind> directSupers = new TreeSet<>();
        for (Class<? extends Annotation> superClazz : subtypeOfMetaAnno.value()) {
            String superName = QualifierKindHierarchy.annotationClassName(superClazz);
            DefaultQualifierKind superQualifier = nameToQualifierKind.get(superName);
            if (superQualifier == null) {
                throw new TypeSystemError("%s @Subtype argument %s isn't in the hierarchy. Qualifiers: [%s]", qualifierKind, superName, StringsPlume.join(", ", qualifierKinds));
            }
            directSupers.add(superQualifier);
        }
        directSuperMap.put(qualifierKind, directSupers);
    }
    return directSuperMap;
}
Also used : TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) Set(java.util.Set) TreeSet(java.util.TreeSet) TypeSystemError(org.checkerframework.javacutil.TypeSystemError) SubtypeOf(org.checkerframework.framework.qual.SubtypeOf) TreeMap(java.util.TreeMap) RequiresNonNull(org.checkerframework.checker.nullness.qual.RequiresNonNull)

Example 4 with TypeSystemError

use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.

the class ValueQualifierHierarchy method leastUpperBound.

/**
 * Determines the least upper bound of a1 and a2, which contains the union of their sets of
 * possible values.
 *
 * @return the least upper bound of a1 and a2
 */
@Override
public AnnotationMirror leastUpperBound(AnnotationMirror a1, AnnotationMirror a2) {
    if (!AnnotationUtils.areSameByName(getTopAnnotation(a1), getTopAnnotation(a2))) {
        // The annotations are in different hierarchies
        return null;
    }
    a1 = atypeFactory.convertSpecialIntRangeToStandardIntRange(a1);
    a2 = atypeFactory.convertSpecialIntRangeToStandardIntRange(a2);
    if (isSubtype(a1, a2)) {
        return a2;
    } else if (isSubtype(a2, a1)) {
        return a1;
    }
    String qual1 = AnnotationUtils.annotationName(a1);
    String qual2 = AnnotationUtils.annotationName(a2);
    if (qual1.equals(qual2)) {
        // If both are the same type, determine the type and merge
        switch(qual1) {
            case ValueAnnotatedTypeFactory.INTRANGE_NAME:
                // special handling for IntRange
                Range intrange1 = atypeFactory.getRange(a1);
                Range intrange2 = atypeFactory.getRange(a2);
                return atypeFactory.createIntRangeAnnotation(intrange1.union(intrange2));
            case ValueAnnotatedTypeFactory.ARRAYLENRANGE_NAME:
                // special handling for ArrayLenRange
                Range range1 = atypeFactory.getRange(a1);
                Range range2 = atypeFactory.getRange(a2);
                return atypeFactory.createArrayLenRangeAnnotation(range1.union(range2));
            case ValueAnnotatedTypeFactory.INTVAL_NAME:
                List<Long> longs = atypeFactory.getIntValues(a1);
                SystemUtil.addWithoutDuplicates(longs, atypeFactory.getIntValues(a2));
                return atypeFactory.createIntValAnnotation(longs);
            case ValueAnnotatedTypeFactory.ARRAYLEN_NAME:
                List<Integer> arrayLens = atypeFactory.getArrayLength(a1);
                SystemUtil.addWithoutDuplicates(arrayLens, atypeFactory.getArrayLength(a2));
                return atypeFactory.createArrayLenAnnotation(arrayLens);
            case ValueAnnotatedTypeFactory.STRINGVAL_NAME:
                List<String> strings = atypeFactory.getStringValues(a1);
                SystemUtil.addWithoutDuplicates(strings, atypeFactory.getStringValues(a2));
                return atypeFactory.createStringAnnotation(strings);
            case ValueAnnotatedTypeFactory.BOOLVAL_NAME:
                List<Boolean> bools = atypeFactory.getBooleanValues(a1);
                SystemUtil.addWithoutDuplicates(bools, atypeFactory.getBooleanValues(a2));
                return atypeFactory.createBooleanAnnotation(bools);
            case ValueAnnotatedTypeFactory.DOUBLEVAL_NAME:
                List<Double> doubles = atypeFactory.getDoubleValues(a1);
                SystemUtil.addWithoutDuplicates(doubles, atypeFactory.getDoubleValues(a2));
                return atypeFactory.createDoubleAnnotation(doubles);
            case ValueAnnotatedTypeFactory.MATCHES_REGEX_NAME:
                List<@Regex String> regexes = atypeFactory.getMatchesRegexValues(a1);
                SystemUtil.addWithoutDuplicates(regexes, atypeFactory.getMatchesRegexValues(a2));
                return atypeFactory.createMatchesRegexAnnotation(regexes);
            default:
                throw new TypeSystemError("default case: %s %s %s%n", qual1, a1, a2);
        }
    }
    // Special handling for dealing with the lub of two annotations that are distinct but
    // convertible (e.g. a StringVal and a MatchesRegex, or an IntVal and an IntRange).
    // Each of these variables is an annotation of the given type, or is null if neither of
    // the arguments to leastUpperBound is of the given types.
    AnnotationMirror arrayLenAnno = null;
    AnnotationMirror arrayLenRangeAnno = null;
    AnnotationMirror stringValAnno = null;
    AnnotationMirror matchesRegexAnno = null;
    AnnotationMirror intValAnno = null;
    AnnotationMirror intRangeAnno = null;
    AnnotationMirror doubleValAnno = null;
    switch(qual1) {
        case ValueAnnotatedTypeFactory.ARRAYLEN_NAME:
            arrayLenAnno = a1;
            break;
        case ValueAnnotatedTypeFactory.ARRAYLENRANGE_NAME:
            arrayLenRangeAnno = a1;
            break;
        case ValueAnnotatedTypeFactory.STRINGVAL_NAME:
            stringValAnno = a1;
            break;
        case ValueAnnotatedTypeFactory.MATCHES_REGEX_NAME:
            matchesRegexAnno = a1;
            break;
        case ValueAnnotatedTypeFactory.INTVAL_NAME:
            intValAnno = a1;
            break;
        case ValueAnnotatedTypeFactory.INTRANGE_NAME:
            intRangeAnno = a1;
            break;
        case ValueAnnotatedTypeFactory.DOUBLEVAL_NAME:
            doubleValAnno = a1;
            break;
        default:
    }
    switch(qual2) {
        case ValueAnnotatedTypeFactory.ARRAYLEN_NAME:
            arrayLenAnno = a2;
            break;
        case ValueAnnotatedTypeFactory.ARRAYLENRANGE_NAME:
            arrayLenRangeAnno = a2;
            break;
        case ValueAnnotatedTypeFactory.STRINGVAL_NAME:
            stringValAnno = a2;
            break;
        case ValueAnnotatedTypeFactory.MATCHES_REGEX_NAME:
            matchesRegexAnno = a2;
            break;
        case ValueAnnotatedTypeFactory.INTVAL_NAME:
            intValAnno = a2;
            break;
        case ValueAnnotatedTypeFactory.INTRANGE_NAME:
            intRangeAnno = a2;
            break;
        case ValueAnnotatedTypeFactory.DOUBLEVAL_NAME:
            doubleValAnno = a2;
            break;
        default:
    }
    // a StringVal with one of them, or a StringVal and a MatchesRegex.
    if (arrayLenAnno != null && arrayLenRangeAnno != null) {
        return leastUpperBound(arrayLenRangeAnno, atypeFactory.convertArrayLenToArrayLenRange(arrayLenAnno));
    } else if (stringValAnno != null && arrayLenAnno != null) {
        return leastUpperBound(arrayLenAnno, atypeFactory.convertStringValToArrayLen(stringValAnno));
    } else if (stringValAnno != null && arrayLenRangeAnno != null) {
        return leastUpperBound(arrayLenRangeAnno, atypeFactory.convertStringValToArrayLenRange(stringValAnno));
    } else if (stringValAnno != null && matchesRegexAnno != null) {
        return leastUpperBound(matchesRegexAnno, atypeFactory.convertStringValToMatchesRegex(stringValAnno));
    }
    if (doubleValAnno != null) {
        if (intRangeAnno != null) {
            intValAnno = atypeFactory.convertIntRangeToIntVal(intRangeAnno);
            if (AnnotationUtils.areSameByName(intValAnno, ValueAnnotatedTypeFactory.UNKNOWN_NAME)) {
                intValAnno = null;
            }
        }
        if (intValAnno != null) {
            // Convert intValAnno to a @DoubleVal AnnotationMirror
            AnnotationMirror doubleValAnno2 = atypeFactory.convertIntValToDoubleVal(intValAnno);
            return leastUpperBound(doubleValAnno, doubleValAnno2);
        }
        return atypeFactory.UNKNOWNVAL;
    }
    if (intRangeAnno != null && intValAnno != null) {
        // Convert intValAnno to an @IntRange AnnotationMirror
        AnnotationMirror intRangeAnno2 = atypeFactory.convertIntValToIntRange(intValAnno);
        return leastUpperBound(intRangeAnno, intRangeAnno2);
    }
    // In all other cases, the LUB is UnknownVal.
    return atypeFactory.UNKNOWNVAL;
}
Also used : TypeSystemError(org.checkerframework.javacutil.TypeSystemError) Range(org.checkerframework.common.value.util.Range) AnnotationMirror(javax.lang.model.element.AnnotationMirror)

Example 5 with TypeSystemError

use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.

the class ValueTreeAnnotator method visitEnumConstant.

/**
 * Default the type of an enum constant {@code E.V} to {@code @StringVal("V")}. Does nothing if
 * the argument is not an enum constant.
 *
 * @param tree an Identifier or MemberSelect tree that might be an enum
 * @param type the type of that tree
 */
private void visitEnumConstant(ExpressionTree tree, AnnotatedTypeMirror type) {
    Element decl = TreeUtils.elementFromTree(tree);
    if (decl.getKind() != ElementKind.ENUM_CONSTANT) {
        return;
    }
    Name id;
    switch(tree.getKind()) {
        case MEMBER_SELECT:
            id = ((MemberSelectTree) tree).getIdentifier();
            break;
        case IDENTIFIER:
            id = ((IdentifierTree) tree).getName();
            break;
        default:
            throw new TypeSystemError("unexpected kind of enum constant use tree: " + tree.getKind());
    }
    AnnotationMirror stringVal = atypeFactory.createStringAnnotation(Collections.singletonList(id.toString()));
    type.replaceAnnotation(stringVal);
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) VariableElement(javax.lang.model.element.VariableElement) Element(javax.lang.model.element.Element) TypeSystemError(org.checkerframework.javacutil.TypeSystemError) BinaryName(org.checkerframework.checker.signature.qual.BinaryName) Name(javax.lang.model.element.Name)

Aggregations

TypeSystemError (org.checkerframework.javacutil.TypeSystemError)23 AnnotationMirror (javax.lang.model.element.AnnotationMirror)6 ExecutableElement (javax.lang.model.element.ExecutableElement)4 Range (org.checkerframework.common.value.util.Range)4 Element (javax.lang.model.element.Element)3 VariableElement (javax.lang.model.element.VariableElement)3 RequiresNonNull (org.checkerframework.checker.nullness.qual.RequiresNonNull)3 ArrayLenRange (org.checkerframework.common.value.qual.ArrayLenRange)3 MethodTree (com.sun.source.tree.MethodTree)2 ArrayList (java.util.ArrayList)2 TypeElement (javax.lang.model.element.TypeElement)2 MustCallAnnotatedTypeFactory (org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory)2 MethodInvocationNode (org.checkerframework.dataflow.cfg.node.MethodInvocationNode)2 ObjectCreationNode (org.checkerframework.dataflow.cfg.node.ObjectCreationNode)2 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)2 AnnotationBuilder (org.checkerframework.javacutil.AnnotationBuilder)2 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)1 ExpressionTree (com.sun.source.tree.ExpressionTree)1 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)1 MemberReferenceTree (com.sun.source.tree.MemberReferenceTree)1