Class QualifierHierarchy

java.lang.Object
org.checkerframework.framework.type.QualifierHierarchy
Direct Known Subclasses:
ElementQualifierHierarchy, NoElementQualifierHierarchy

@AnnotatedFor("nullness") public abstract class QualifierHierarchy extends Object
Represents multiple type qualifier hierarchies. getWidth() gives the number of hierarchies that this object represents. Each hierarchy has its own top and bottom, and subtyping relationships exist only within each hierarchy.

Note the distinction in terminology between a qualifier hierarchy, which has one top and one bottom, and a QualifierHierarchy, which represents multiple qualifier hierarchies.

All type annotations need to be type qualifiers recognized within this hierarchy.

This assumes that every annotated type in a program is annotated with exactly one qualifier from each hierarchy.

  • Field Details

    • atypeFactory

      protected GenericAnnotatedTypeFactory<?,?,?,?> atypeFactory
      The associated type factory. This is used only for checking whether types are relevant.
  • Constructor Details

    • QualifierHierarchy

      public QualifierHierarchy(GenericAnnotatedTypeFactory<?,?,?,?> atypeFactory)
      Creates a new QualifierHierarchy.
      Parameters:
      atypeFactory - the associated type factory
  • Method Details

    • isValid

      public boolean isValid()
      Determine whether this QualifierHierarchy is valid.
      Returns:
      true if this QualifierHierarchy is valid
    • getWidth

      public int getWidth()
      Returns the width of this hierarchy, i.e. the expected number of annotations on any valid type.
      Returns:
      the width of this QualifierHierarchy
    • getTopAnnotations

      public abstract AnnotationMirrorSet getTopAnnotations()
      Returns the top (ultimate super) type qualifiers in the type system. The size of this set is equal to getWidth().
      Returns:
      the top (ultimate super) type qualifiers in the type system
    • getTopAnnotation

      public abstract AnnotationMirror getTopAnnotation(AnnotationMirror qualifier)
      Return the top qualifier for the given qualifier, that is, the qualifier that is a supertype of qualifier but no further supertypes exist.
      Parameters:
      qualifier - any qualifier from one of the qualifier hierarchies represented by this
      Returns:
      the top qualifier of qualifier's hierarchy
    • getBottomAnnotations

      public abstract AnnotationMirrorSet getBottomAnnotations()
      Returns the bottom type qualifiers in the hierarchy. The size of this set is equal to getWidth().
      Returns:
      the bottom type qualifiers in the hierarchy
    • getBottomAnnotation

      public abstract AnnotationMirror getBottomAnnotation(AnnotationMirror qualifier)
      Return the bottom for the given qualifier, that is, the qualifier that is a subtype of qualifier but no further subtypes exist.
      Parameters:
      qualifier - any qualifier from one of the qualifier hierarchies represented by this
      Returns:
      the bottom qualifier of qualifier's hierarchy
    • getPolymorphicAnnotation

      public abstract @Nullable AnnotationMirror getPolymorphicAnnotation(AnnotationMirror qualifier)
      Returns the polymorphic qualifier for the hierarchy containing qualifier, or null if there is no polymorphic qualifier in that hierarchy.
      Parameters:
      qualifier - any qualifier from one of the qualifier hierarchies represented by this
      Returns:
      the polymorphic qualifier for the hierarchy containing qualifier, or null if there is no polymorphic qualifier in that hierarchy
    • isPolymorphicQualifier

      public abstract boolean isPolymorphicQualifier(AnnotationMirror qualifier)
      Returns true if the qualifier is a polymorphic qualifier; otherwise, returns false.
      Parameters:
      qualifier - qualifier
      Returns:
      true if the qualifier is a polymorphic qualifier; otherwise, returns false.
    • isSubtypeQualifiers

      protected abstract boolean isSubtypeQualifiers(AnnotationMirror subQualifier, AnnotationMirror superQualifier)
      Tests whether subQualifier is equal to or a sub-qualifier of superQualifier, according to the type qualifier hierarchy, ignoring Java basetypes.

      Clients should generally call isSubtypeShallow(javax.lang.model.element.AnnotationMirror, javax.lang.model.type.TypeMirror, javax.lang.model.element.AnnotationMirror, javax.lang.model.type.TypeMirror). However, subtypes should generally override this method (if needed).

      This method behaves the same as isSubtypeQualifiersOnly(AnnotationMirror, AnnotationMirror), which calls this method. This method is for clients inside the framework, and it has protected access to prevent use by clients outside the framework. This makes it easy to find places where code outside the framework is ignoring Java basetypes -- at calls to isSubtypeQualifiersOnly(javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationMirror).

      Parameters:
      subQualifier - possible subqualifier
      superQualifier - possible superqualifier
      Returns:
      true iff subQualifier is a subqualifier of, or equal to, superQualifier
    • isSubtypeQualifiersOnly

      public final boolean isSubtypeQualifiersOnly(AnnotationMirror subQualifier, AnnotationMirror superQualifier)
      Tests whether subQualifier is equal to or a sub-qualifier of superQualifier, according to the type qualifier hierarchy, ignoring Java basetypes.

      This method is for clients outside the framework, and should not be used by framework code.

      Parameters:
      subQualifier - possible subqualifier
      superQualifier - possible superqualifier
      Returns:
      true iff subQualifier is a subqualifier of, or equal to, superQualifier
    • isSubtypeShallow

      public boolean isSubtypeShallow(AnnotationMirror subQualifier, TypeMirror subType, AnnotationMirror superQualifier, TypeMirror superType)
      Tests whether subQualifier is equal to or a sub-qualifier of superQualifier, according to the type qualifier hierarchy. The types subType and superType are not necessarily in a Java subtyping relationship with one another and are only used by this method for special cases when qualifier subtyping depends on the Java basetype.

      Clients should usually call isSubtypeShallow() (this method). Rarely, to ignore the Java basetype, a client can call isSubtypeQualifiersOnly(javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationMirror).

      Subtypes should override isSubtypeQualifiers(javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationMirror) (not this method), unless qualifier subtyping depends on Java basetypes.

      Parameters:
      subQualifier - possible subqualifier
      subType - the Java basetype associated with subQualifier
      superQualifier - possible superqualifier
      superType - the Java basetype associated with superQualifier
      Returns:
      true iff subQualifier is a subqualifier of, or equal to, superQualifier
    • isSubtypeShallow

      public final boolean isSubtypeShallow(AnnotationMirror subQualifier, AnnotationMirror superQualifier, TypeMirror typeMirror)
      Tests whether subQualifier is equal to or a sub-qualifier of superQualifier, according to the type qualifier hierarchy. The type typeMirror is only used by this method for special cases when qualifier subtyping depends on the Java basetype.

      Clients should usually call isSubtypeShallow(AnnotationMirror, AnnotationMirror, TypeMirror) (this method) or isSubtypeShallow(AnnotationMirror, TypeMirror, AnnotationMirror, TypeMirror). Rarely, to ignore the Java basetype, a client can call isSubtypeQualifiersOnly(javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationMirror).

      Subtypes should override isSubtypeQualifiers(javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationMirror) (not this method), unless qualifier subtyping depends on Java basetypes.

      Parameters:
      subQualifier - possible subqualifier
      superQualifier - possible superqualifier
      typeMirror - the Java basetype associated with both subQualifier and superQualifier
      Returns:
      true iff subQualifier is a subqualifier of, or equal to, superQualifier
    • isSubtypeShallow

      public final boolean isSubtypeShallow(Collection<? extends AnnotationMirror> subQualifiers, TypeMirror subType, Collection<? extends AnnotationMirror> superQualifiers, TypeMirror superType)
      Tests whether all qualifiers in subQualifiers are a subqualifier or equal to the qualifier in the same hierarchy in superQualifiers. The types subType and superType are not necessarily in a Java subtyping relationship with one another and are only used by this method for special cases when qualifier subtyping depends on the Java basetype.

      Subtypes more often override isSubtypeShallow(AnnotationMirror, TypeMirror, AnnotationMirror, TypeMirror) than this method.

      Parameters:
      subQualifiers - set of qualifiers; exactly one per hierarchy
      subType - the type associated with subQualifiers
      superQualifiers - set of qualifiers; exactly one per hierarchy
      superType - the type associated with superQualifiers
      Returns:
      true iff all qualifiers in subQualifiers are a subqualifier or equal to the qualifier in the same hierarchy in superQualifiers
    • isSubtypeShallow

      public final boolean isSubtypeShallow(Collection<? extends AnnotationMirror> subQualifiers, Collection<? extends AnnotationMirror> superQualifiers, TypeMirror typeMirror)
      Tests whether all qualifiers in subQualifiers are a subqualifier of or equal to the qualifier in the same hierarchy in superQualifiers. The type typeMirror is only used by this method for special cases when qualifier subtyping depends on the Java basetype.

      Subtypes more often override isSubtypeShallow(AnnotationMirror, TypeMirror, AnnotationMirror, TypeMirror) than this method.

      Parameters:
      subQualifiers - a set of qualifiers; exactly one per hierarchy
      superQualifiers - a set of qualifiers; exactly one per hierarchy
      typeMirror - the type associated with both sets of qualifiers
      Returns:
      true iff all qualifiers in subQualifiers are a subqualifier or equal to the qualifier in the same hierarchy in superQualifiers
    • leastUpperBoundQualifiers

      protected abstract @Nullable AnnotationMirror leastUpperBoundQualifiers(AnnotationMirror qualifier1, AnnotationMirror qualifier2)
      Returns the least upper bound (LUB) of the qualifiers qualifier1 and qualifier2. Returns null if the qualifiers are not from the same qualifier hierarchy. Ignores Java basetypes.

      Examples:

      • For NonNull, leastUpperBound('Nullable', 'NonNull') ⇒ Nullable
      Parameters:
      qualifier1 - the first qualifier; may not be in the same hierarchy as qualifier2
      qualifier2 - the second qualifier; may not be in the same hierarchy as qualifier1
      Returns:
      the least upper bound of the qualifiers, or null if the qualifiers are from different hierarchies
    • leastUpperBoundQualifiersOnly

      public final @Nullable AnnotationMirror leastUpperBoundQualifiersOnly(AnnotationMirror qualifier1, AnnotationMirror qualifier2)
      Returns the least upper bound (LUB) of the qualifiers qualifier1 and qualifier2. Returns null if the qualifiers are not from the same qualifier hierarchy. Ignores Java basetypes.

      Examples:

      • For NonNull, leastUpperBound('Nullable', 'NonNull') ⇒ Nullable
      Parameters:
      qualifier1 - the first qualifier; may not be in the same hierarchy as qualifier2
      qualifier2 - the second qualifier; may not be in the same hierarchy as qualifier1
      Returns:
      the least upper bound of the qualifiers, or null if the qualifiers are from different hierarchies
    • leastUpperBoundShallow

      public @Nullable AnnotationMirror leastUpperBoundShallow(AnnotationMirror qualifier1, TypeMirror tm1, AnnotationMirror qualifier2, TypeMirror tm2)
      Returns the least upper bound (LUB) of the qualifiers qualifier1 and qualifier2. Returns null if the qualifiers are not from the same qualifier hierarchy.

      Examples:

      • leastUpperBound('Nullable', 'NonNull') ⇒ Nullable
      Parameters:
      qualifier1 - the first qualifier; may not be in the same hierarchy as qualifier2
      tm1 - the type on which qualifier1 appears
      qualifier2 - the second qualifier; may not be in the same hierarchy as qualifier1
      tm2 - the type on which qualifier2 appears
      Returns:
      the least upper bound of the qualifiers, or null if the qualifiers are from different hierarchies
    • leastUpperBoundsShallow

      public final Set<? extends AnnotationMirror> leastUpperBoundsShallow(Collection<? extends AnnotationMirror> qualifiers1, TypeMirror tm1, Collection<? extends AnnotationMirror> qualifiers2, TypeMirror tm2)
      Returns the least upper bound of the two sets of qualifiers. The result is the lub of the qualifier for the same hierarchy in each set.
      Parameters:
      qualifiers1 - set of qualifiers; exactly one per hierarchy
      tm1 - the type on which qualifiers1 appear
      qualifiers2 - set of qualifiers; exactly one per hierarchy
      tm2 - the type on which qualifiers2 appear
      Returns:
      the least upper bound of the two sets of qualifiers
    • numberOfIterationsBeforeWidening

      public int numberOfIterationsBeforeWidening()
      Returns the number of iterations dataflow should perform before widenedUpperBound(AnnotationMirror, AnnotationMirror) is called or -1 if it should never be called.
      Returns:
      the number of iterations dataflow should perform before widenedUpperBound(AnnotationMirror, AnnotationMirror) is called or -1 if it should never be called.
    • widenedUpperBound

      public AnnotationMirror widenedUpperBound(AnnotationMirror newQualifier, AnnotationMirror previousQualifier)
      If the qualifier hierarchy has an infinite ascending chain, then the dataflow analysis might never reach a fixed point. To prevent this, implement this method such that it returns an upper bound for the two qualifiers that is a strict super type of the least upper bound. If this method is implemented, also override numberOfIterationsBeforeWidening() to return a positive number.

      newQualifier is newest qualifier dataflow computed for some expression and previousQualifier is the qualifier dataflow computed on the last iteration.

      If the qualifier hierarchy has no infinite ascending chain, returns the least upper bound of the two annotations.

      Parameters:
      newQualifier - new qualifier dataflow computed for some expression; must be in the same hierarchy as previousQualifier
      previousQualifier - the previous qualifier dataflow computed on the last iteration; must be in the same hierarchy as previousQualifier
      Returns:
      an upper bound that is higher than the least upper bound of newQualifier and previousQualifier (or the lub if the qualifier hierarchy does not require this)
    • greatestLowerBoundQualifiers

      protected abstract @Nullable AnnotationMirror greatestLowerBoundQualifiers(AnnotationMirror qualifier1, AnnotationMirror qualifier2)
      Returns the greatest lower bound for the qualifiers qualifier1 and qualifier2. Returns null if the qualifiers are not from the same qualifier hierarchy.
      Parameters:
      qualifier1 - first qualifier
      qualifier2 - second qualifier
      Returns:
      greatest lower bound of the two annotations, or null if the two annotations are not from the same hierarchy
    • greatestLowerBoundQualifiersOnly

      public final @Nullable AnnotationMirror greatestLowerBoundQualifiersOnly(AnnotationMirror qualifier1, AnnotationMirror qualifier2)
      Returns the greatest lower bound for the qualifiers qualifier1 and qualifier2. Returns null if the qualifiers are not from the same qualifier hierarchy.
      Parameters:
      qualifier1 - first qualifier
      qualifier2 - second qualifier
      Returns:
      greatest lower bound of the two annotations, or null if the two annotations are not from the same hierarchy
    • greatestLowerBoundShallow

      public @Nullable AnnotationMirror greatestLowerBoundShallow(AnnotationMirror qualifier1, TypeMirror tm1, AnnotationMirror qualifier2, TypeMirror tm2)
      Returns the greatest lower bound for the qualifiers qualifier1 and qualifier2. Returns null if the qualifiers are not from the same qualifier hierarchy.
      Parameters:
      qualifier1 - first qualifier
      tm1 - the type that is annotated by qualifier1
      qualifier2 - second qualifier
      tm2 - the type that is annotated by qualifier2
      Returns:
      greatest lower bound of the two annotations, or null if the two annotations are not from the same hierarchy
    • greatestLowerBoundsShallow

      public final Set<? extends AnnotationMirror> greatestLowerBoundsShallow(Collection<? extends AnnotationMirror> qualifiers1, TypeMirror tm1, Collection<? extends AnnotationMirror> qualifiers2, TypeMirror tm2)
      Returns the greatest lower bound of the two sets of qualifiers. The result is the lub of the qualifier for the same hierarchy in each set.
      Parameters:
      qualifiers1 - set of qualifiers; exactly one per hierarchy
      tm1 - the type that is annotated by qualifier1
      qualifiers2 - set of qualifiers; exactly one per hierarchy
      tm2 - the type that is annotated by qualifier2
      Returns:
      the greatest lower bound of the two sets of qualifiers
    • canHaveEmptyAnnotationSet

      public static boolean canHaveEmptyAnnotationSet(AnnotatedTypeMirror type)
      Returns true if and only if AnnotatedTypeMirror.getPrimaryAnnotations() can return a set with fewer qualifiers than the width of the QualifierHierarchy.
      Parameters:
      type - the type to test
      Returns:
      true if and only if AnnotatedTypeMirror.getPrimaryAnnotations() can return a set with fewer qualifiers than the width of the QualifierHierarchy
    • findAnnotationInSameHierarchy

      public @Nullable AnnotationMirror findAnnotationInSameHierarchy(Collection<? extends AnnotationMirror> qualifiers, AnnotationMirror qualifier)
      Returns the annotation in qualifiers that is in the same hierarchy as qualifier.

      The default implementation calls getTopAnnotation(AnnotationMirror) and then calls findAnnotationInHierarchy(Collection, AnnotationMirror). So, if qualifier is a top qualifier, then call findAnnotationInHierarchy(Collection, AnnotationMirror) directly is faster.

      Parameters:
      qualifiers - set of annotations to search
      qualifier - annotation that is in the same hierarchy as the returned annotation
      Returns:
      annotation in the same hierarchy as qualifier, or null if one is not found
    • findAnnotationInHierarchy

      public @Nullable AnnotationMirror findAnnotationInHierarchy(Collection<? extends AnnotationMirror> qualifiers, AnnotationMirror top)
      Returns the annotation in qualifiers that is in the hierarchy for which top is top.
      Parameters:
      qualifiers - set of annotations to search
      top - the top annotation in the hierarchy to which the returned annotation belongs
      Returns:
      annotation in the same hierarchy as annotationMirror, or null if one is not found
    • updateMappingToMutableSet

      public <T> boolean updateMappingToMutableSet(Map<T,AnnotationMirrorSet> map, T key, AnnotationMirror qualifier)
      Update a mapping from key to a set of AnnotationMirrors. If key is not already in the map, then put it in the map with a value of a new set containing qualifier. If the map contains key, then add qualifier to the set to which key maps. If that set contains a qualifier in the same hierarchy as qualifier, then don't add it and return false.
      Type Parameters:
      T - type of the map's keys
      Parameters:
      map - the mapping to modify
      key - the key to update or add
      qualifier - the value to update or add
      Returns:
      true if the update was done; false if there was a qualifier hierarchy collision
    • assertSameSize

      public static void assertSameSize(Collection<?> c1, Collection<?> c2)
      Throws an exception if the given collections do not have the same size.
      Parameters:
      c1 - the first collection
      c2 - the second collection
    • assertSameSize

      public static void assertSameSize(Collection<? extends Object> c1, Collection<? extends Object> c2, Collection<? extends Object> result)
      Throws an exception if the result and the inputs do not all have the same size.
      Parameters:
      c1 - the first collection
      c2 - the second collection
      result - the result collection