Search in sources :

Example 21 with QualifierHierarchy

use of org.checkerframework.framework.type.QualifierHierarchy in project checker-framework by typetools.

the class ConstraintMapBuilder method build.

/**
 * Let Ti be a the ith target being inferred Let ATV(i) be the annotated type variable that
 * represents as use of Ti which may or may not have primary annotations. Let ATM be an
 * annotated type mirror that may or may not be target Tx, or have a component target Tx Let Ai
 * be the type argument we are trying to infer for Ti
 *
 * <p>We have a set of constraints of the form: {@code ATV(i) <?> ATM}
 *
 * <p>Where {@code <?>} is either a subtype ({@code <:}), supertype ({@code :>}), or equality
 * relationship ({@code =}).
 *
 * <p>Regardless of what {@code <?>} is, a constraint will only imply constraints on Ai in a
 * given hierarchy if ATV(i) does NOT have a primary annotation in that hierarchy. That is:
 *
 * <p>E.g. Let ATV(i) be @NonNull Ti, the constraints @NonNull Ti = @NonNull @Initialized String
 * does not imply any primary annotation in the Nullness hierarchy for type argument Ai because
 * the Annotated type mirror has a primary annotation in the NUllness hierarchy.
 *
 * <p>However, it does imply that Ai has a primary annotation of @Initialized since ATV(i) has
 * no primary annotation in the initialization hierarchy.
 *
 * <p>Note, constraints come in 2 forms:
 *
 * <ul>
 *   <li>between a target and a concrete AnnotatedTypeMirror. E.g., As seen above {@code
 *       (@NonNull Ti = @NonNull @Initialized String)}
 *   <li>between two targets E.g., {@code (@NonNull Ti = Tj)}
 * </ul>
 */
public ConstraintMap build(Set<TypeVariable> targets, Set<TUConstraint> constraints, AnnotatedTypeFactory typeFactory) {
    final QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
    final AnnotationMirrorSet tops = new AnnotationMirrorSet(qualifierHierarchy.getTopAnnotations());
    final ConstraintMap result = new ConstraintMap(targets);
    final AnnotationMirrorSet tAnnos = new AnnotationMirrorSet();
    final AnnotationMirrorSet uAnnos = new AnnotationMirrorSet();
    final AnnotationMirrorSet hierarchiesInRelation = new AnnotationMirrorSet();
    for (TUConstraint constraint : constraints) {
        tAnnos.clear();
        uAnnos.clear();
        hierarchiesInRelation.clear();
        final AnnotatedTypeVariable typeT = constraint.typeVariable;
        final AnnotatedTypeMirror typeU = constraint.relatedType;
        // The inferred type of T should be T.
        if (!constraint.uIsArg && typeU.getKind() == TypeKind.TYPEVAR && targets.contains((TypeVariable) TypeAnnotationUtils.unannotatedType(typeU.getUnderlyingType()))) {
            if (typeT.getAnnotations().isEmpty() && typeU.getAnnotations().isEmpty()) {
                hierarchiesInRelation.addAll(tops);
            } else {
                for (AnnotationMirror top : tops) {
                    final AnnotationMirror tAnno = typeT.getAnnotationInHierarchy(top);
                    final AnnotationMirror uAnno = typeU.getAnnotationInHierarchy(top);
                    if (tAnno == null) {
                        if (uAnno == null) {
                            hierarchiesInRelation.add(top);
                        } else {
                            tAnnos.add(uAnno);
                        }
                    } else {
                        if (uAnno == null) {
                            uAnnos.add(tAnno);
                        } else {
                        // This tells us nothing, they both should be equal but either way
                        // we gain no information if both type vars have annotations
                        }
                    }
                }
                // This case also covers the case where i = j.
                if (!tAnnos.isEmpty()) {
                    addToPrimaryRelationship((TypeVariable) TypeAnnotationUtils.unannotatedType(typeT.getUnderlyingType()), constraint, result, tAnnos, qualifierHierarchy);
                }
                if (!uAnnos.isEmpty()) {
                    addToPrimaryRelationship((TypeVariable) TypeAnnotationUtils.unannotatedType(typeU.getUnderlyingType()), constraint, result, uAnnos, qualifierHierarchy);
                }
            }
            // <?> Tj and i != j)
            if (!TypeAnnotationUtils.unannotatedType(typeT.getUnderlyingType()).equals(TypeAnnotationUtils.unannotatedType(typeU.getUnderlyingType()))) {
                addToTargetRelationship((TypeVariable) TypeAnnotationUtils.unannotatedType(typeT.getUnderlyingType()), (TypeVariable) TypeAnnotationUtils.unannotatedType(typeU.getUnderlyingType()), result, constraint, hierarchiesInRelation);
            }
        } else {
            for (AnnotationMirror top : tops) {
                final AnnotationMirror tAnno = typeT.getAnnotationInHierarchy(top);
                if (tAnno == null) {
                    hierarchiesInRelation.add(top);
                }
            }
            addToTypeRelationship((TypeVariable) TypeAnnotationUtils.unannotatedType(typeT.getUnderlyingType()), typeU, result, constraint, hierarchiesInRelation);
        }
    }
    return result;
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) TypeVariable(javax.lang.model.type.TypeVariable) QualifierHierarchy(org.checkerframework.framework.type.QualifierHierarchy) AnnotationMirrorSet(org.checkerframework.framework.util.AnnotationMirrorSet) TUConstraint(org.checkerframework.framework.util.typeinference.constraint.TUConstraint) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 22 with QualifierHierarchy

use of org.checkerframework.framework.type.QualifierHierarchy in project checker-framework by typetools.

the class SupertypesSolver method targetToTypeLubs.

/**
 * For each target, lub all of the types/annotations in its supertypes constraints and return
 * the lubs
 *
 * @param remainingTargets targets that do not already have an inferred type argument
 * @param constraintMap the set of constraints for all targets
 * @return the lub determined for each target that has at least 1 supertype constraint
 */
private Lubs targetToTypeLubs(Set<TypeVariable> remainingTargets, ConstraintMap constraintMap, AnnotatedTypeFactory typeFactory) {
    final QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
    final AnnotationMirrorSet tops = new AnnotationMirrorSet(qualifierHierarchy.getTopAnnotations());
    Lubs solution = new Lubs();
    AnnotationMirrorMap<AnnotationMirror> lubOfPrimaries = new AnnotationMirrorMap<>();
    List<TypeVariable> targetsSupertypesLast = new ArrayList<>(remainingTargets);
    final Types types = typeFactory.getProcessingEnv().getTypeUtils();
    // If we have two type variables <A, A extends B> order them B then A
    // this is required because we will use the fact that A must be above B
    // when determining the LUB of A
    Collections.sort(targetsSupertypesLast, new Comparator<TypeVariable>() {

        @Override
        public int compare(TypeVariable o1, TypeVariable o2) {
            if (types.isSubtype(o1, o2)) {
                return -1;
            } else if (types.isSubtype(o2, o1)) {
                return 1;
            }
            return 0;
        }
    });
    for (final TypeVariable target : targetsSupertypesLast) {
        TargetConstraints targetRecord = constraintMap.getConstraints(target);
        final AnnotationMirrorMap<AnnotationMirrorSet> subtypeAnnos = targetRecord.supertypes.primaries;
        final Map<AnnotatedTypeMirror, AnnotationMirrorSet> subtypesOfTarget = targetRecord.supertypes.types;
        // If this target is a supertype of other targets and those targets have already been
        // lubbed add that LUB to the list of lubs for this target (as it must be above this
        // target).
        propagatePreviousLubs(targetRecord, solution, subtypesOfTarget);
        // lub all the primary annotations and put them in lubOfPrimaries
        lubPrimaries(lubOfPrimaries, subtypeAnnos, tops, qualifierHierarchy);
        solution.addPrimaries(target, lubOfPrimaries);
        if (subtypesOfTarget.keySet().size() > 0) {
            final AnnotatedTypeMirror lub = leastUpperBound(target, typeFactory, subtypesOfTarget);
            final AnnotationMirrorSet effectiveLubAnnos = new AnnotationMirrorSet(lub.getEffectiveAnnotations());
            for (AnnotationMirror lubAnno : effectiveLubAnnos) {
                final AnnotationMirror hierarchy = qualifierHierarchy.getTopAnnotation(lubAnno);
                final AnnotationMirror primaryLub = lubOfPrimaries.get(hierarchy);
                if (primaryLub != null) {
                    if (qualifierHierarchy.isSubtype(lubAnno, primaryLub) && !AnnotationUtils.areSame(lubAnno, primaryLub)) {
                        lub.replaceAnnotation(primaryLub);
                    }
                }
            }
            solution.addType(target, lub);
        }
    }
    return solution;
}
Also used : Types(javax.lang.model.util.Types) AnnotatedTypes(org.checkerframework.framework.util.AnnotatedTypes) AnnotationMirrorMap(org.checkerframework.framework.util.AnnotationMirrorMap) ArrayList(java.util.ArrayList) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) AnnotationMirror(javax.lang.model.element.AnnotationMirror) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) TypeVariable(javax.lang.model.type.TypeVariable) QualifierHierarchy(org.checkerframework.framework.type.QualifierHierarchy) AnnotationMirrorSet(org.checkerframework.framework.util.AnnotationMirrorSet)

Example 23 with QualifierHierarchy

use of org.checkerframework.framework.type.QualifierHierarchy in project checker-framework by typetools.

the class SupertypesSolver method leastUpperBound.

/**
 * Successively calls least upper bound on the elements of types. Unlike
 * AnnotatedTypes.leastUpperBound, this method will box primitives if necessary
 */
public static AnnotatedTypeMirror leastUpperBound(final TypeVariable target, final AnnotatedTypeFactory typeFactory, final Map<AnnotatedTypeMirror, AnnotationMirrorSet> types) {
    QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
    AnnotatedTypeVariable targetsDeclaredType = (AnnotatedTypeVariable) typeFactory.getAnnotatedType(target.asElement());
    final AnnotationMirrorMap<AnnotationMirror> lowerBoundAnnos = TypeArgInferenceUtil.createHierarchyMap(new AnnotationMirrorSet(targetsDeclaredType.getLowerBound().getEffectiveAnnotations()), qualifierHierarchy);
    final Iterator<Entry<AnnotatedTypeMirror, AnnotationMirrorSet>> typesIter = types.entrySet().iterator();
    if (!typesIter.hasNext()) {
        ErrorReporter.errorAbort("Calling LUB on empty list!");
    }
    /**
     * If a constraint implies that a type parameter Ti is a supertype of an annotated type
     * mirror Ai but only in a subset of all qualifier hierarchies then for all other qualifier
     * hierarchies replace the primary annotation on Ai with the lowest possible annotation
     * (ensuring that it won't be the LUB unless there are no other constraints, or all other
     * constraints imply the bottom annotation is the LUB). Note: Even if we choose bottom as
     * the lub here, the assignment context may raise this annotation.
     */
    final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> head = typesIter.next();
    AnnotatedTypeMirror lubType = groundMissingHierarchies(head, lowerBoundAnnos);
    AnnotatedTypeMirror nextType = null;
    while (typesIter.hasNext()) {
        nextType = groundMissingHierarchies(typesIter.next(), lowerBoundAnnos);
        if (lubType.getKind().isPrimitive()) {
            if (!nextType.getKind().isPrimitive()) {
                lubType = typeFactory.getBoxedType((AnnotatedPrimitiveType) lubType);
            }
        } else if (nextType.getKind().isPrimitive()) {
            if (!lubType.getKind().isPrimitive()) {
                nextType = typeFactory.getBoxedType((AnnotatedPrimitiveType) nextType);
            }
        }
        lubType = AnnotatedTypes.leastUpperBound(typeFactory, lubType, nextType);
    }
    return lubType;
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) Entry(java.util.Map.Entry) QualifierHierarchy(org.checkerframework.framework.type.QualifierHierarchy) AnnotationMirrorSet(org.checkerframework.framework.util.AnnotationMirrorSet) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) AnnotatedPrimitiveType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType)

Example 24 with QualifierHierarchy

use of org.checkerframework.framework.type.QualifierHierarchy in project checker-framework by typetools.

the class BaseTypeVisitor method checkPreconditions.

/**
 * Checks that all the given {@code preconditions} hold true immediately prior to the method
 * invocation or variable access at {@code tree}.
 *
 * @param tree the Tree immediately prior to which the preconditions must hold true
 * @param preconditions the preconditions to be checked
 */
protected void checkPreconditions(MethodInvocationTree tree, Set<Precondition> preconditions) {
    // TODO: Remove this check and investigate the root cause.
    if (preconditions.isEmpty()) {
        return;
    }
    FlowExpressionContext flowExprContext = FlowExpressionContext.buildContextForMethodUse(tree, checker.getContext());
    if (flowExprContext == null) {
        checker.report(Result.failure("flowexpr.parse.context.not.determined", tree), tree);
        return;
    }
    for (Precondition p : preconditions) {
        String expression = p.expression;
        AnnotationMirror anno = p.annotation;
        anno = standardizeAnnotationFromContract(anno, flowExprContext, getCurrentPath());
        try {
            FlowExpressions.Receiver expr = FlowExpressionParseUtil.parse(expression, flowExprContext, getCurrentPath(), false);
            CFAbstractStore<?, ?> store = atypeFactory.getStoreBefore(tree);
            CFAbstractValue<?> value = store.getValue(expr);
            AnnotationMirror inferredAnno = null;
            if (value != null) {
                QualifierHierarchy hierarchy = atypeFactory.getQualifierHierarchy();
                Set<AnnotationMirror> annos = value.getAnnotations();
                inferredAnno = hierarchy.findAnnotationInSameHierarchy(annos, anno);
            }
            if (!checkContract(expr, anno, inferredAnno, store)) {
                checker.report(Result.failure("contracts.precondition.not.satisfied", tree.toString(), expr == null ? expression : expr.toString()), tree);
            }
        } catch (FlowExpressionParseException e) {
            // report errors here
            checker.report(e.getResult(), tree);
        }
    }
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) FlowExpressionContext(org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext) Precondition(org.checkerframework.framework.util.ContractsUtils.Precondition) QualifierHierarchy(org.checkerframework.framework.type.QualifierHierarchy) FlowExpressions(org.checkerframework.dataflow.analysis.FlowExpressions) FlowExpressionParseException(org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver)

Example 25 with QualifierHierarchy

use of org.checkerframework.framework.type.QualifierHierarchy in project checker-framework by typetools.

the class BaseTypeVisitor method isTypeCastSafe.

private boolean isTypeCastSafe(AnnotatedTypeMirror castType, AnnotatedTypeMirror exprType) {
    QualifierHierarchy qualifierHierarchy = atypeFactory.getQualifierHierarchy();
    if (castType.getKind() == TypeKind.DECLARED) {
        // eliminate false positives, where the annotations are
        // implicitly added by the declared type declaration
        AnnotatedDeclaredType castDeclared = (AnnotatedDeclaredType) castType;
        AnnotatedDeclaredType elementType = atypeFactory.fromElement((TypeElement) castDeclared.getUnderlyingType().asElement());
        if (AnnotationUtils.areSame(castDeclared.getAnnotations(), elementType.getAnnotations())) {
            return true;
        }
    }
    if (checker.hasOption("checkCastElementType")) {
        AnnotatedTypeMirror newCastType;
        if (castType.getKind() == TypeKind.TYPEVAR) {
            newCastType = ((AnnotatedTypeVariable) castType).getUpperBound();
        } else {
            newCastType = castType;
        }
        AnnotatedTypeMirror newExprType;
        if (exprType.getKind() == TypeKind.TYPEVAR) {
            newExprType = ((AnnotatedTypeVariable) exprType).getUpperBound();
        } else {
            newExprType = exprType;
        }
        if (!atypeFactory.getTypeHierarchy().isSubtype(newExprType, newCastType)) {
            return false;
        }
        if (newCastType.getKind() == TypeKind.ARRAY && newExprType.getKind() != TypeKind.ARRAY) {
            // doesn't, as in "(Object[]) o" where o is of type Object
            return false;
        } else if (newCastType.getKind() == TypeKind.DECLARED && newExprType.getKind() == TypeKind.DECLARED) {
            int castSize = ((AnnotatedDeclaredType) newCastType).getTypeArguments().size();
            int exprSize = ((AnnotatedDeclaredType) newExprType).getTypeArguments().size();
            if (castSize != exprSize) {
                // TODO: the same number of arguments actually doesn't guarantee anything.
                return false;
            }
        } else if (castType.getKind() == TypeKind.TYPEVAR && exprType.getKind() == TypeKind.TYPEVAR) {
            // If both the cast type and the casted expression are type variables, then check
            // the bounds.
            Set<AnnotationMirror> lowerBoundAnnotationsCast = AnnotatedTypes.findEffectiveLowerBoundAnnotations(qualifierHierarchy, castType);
            Set<AnnotationMirror> lowerBoundAnnotationsExpr = AnnotatedTypes.findEffectiveLowerBoundAnnotations(qualifierHierarchy, exprType);
            return qualifierHierarchy.isSubtype(lowerBoundAnnotationsExpr, lowerBoundAnnotationsCast) && qualifierHierarchy.isSubtype(exprType.getEffectiveAnnotations(), castType.getEffectiveAnnotations());
        }
        Set<AnnotationMirror> castAnnos;
        if (castType.getKind() == TypeKind.TYPEVAR) {
            // If the cast type is a type var, but the expression is not, then check that the
            // type of the expression is a subtype of the lower bound.
            castAnnos = AnnotatedTypes.findEffectiveLowerBoundAnnotations(qualifierHierarchy, castType);
        } else {
            castAnnos = castType.getAnnotations();
        }
        return qualifierHierarchy.isSubtype(exprType.getEffectiveAnnotations(), castAnnos);
    } else {
        // checkCastElementType option wasn't specified, so only check effective annotations,
        return qualifierHierarchy.isSubtype(exprType.getEffectiveAnnotations(), castType.getEffectiveAnnotations());
    }
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) QualifierHierarchy(org.checkerframework.framework.type.QualifierHierarchy) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Aggregations

QualifierHierarchy (org.checkerframework.framework.type.QualifierHierarchy)25 AnnotationMirror (javax.lang.model.element.AnnotationMirror)22 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)9 AnnotationMirrorSet (org.checkerframework.framework.util.AnnotationMirrorSet)6 ArrayList (java.util.ArrayList)4 AnnotatedTypeVariable (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable)4 TypeVariable (javax.lang.model.type.TypeVariable)3 Elements (javax.lang.model.util.Elements)3 Types (javax.lang.model.util.Types)3 Receiver (org.checkerframework.dataflow.analysis.FlowExpressions.Receiver)3 TypeUseLocation (org.checkerframework.framework.qual.TypeUseLocation)2 AnnotationMirrorMap (org.checkerframework.framework.util.AnnotationMirrorMap)2 InferredType (org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType)2 AnnotationBuilder (org.checkerframework.javacutil.AnnotationBuilder)2 MethodTree (com.sun.source.tree.MethodTree)1 Entry (java.util.Map.Entry)1 TypeMirror (javax.lang.model.type.TypeMirror)1 A (lubglb.quals.A)1 B (lubglb.quals.B)1 C (lubglb.quals.C)1