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;
}
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;
}
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;
}
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);
}
}
}
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());
}
}
Aggregations