/**
   * {@inheritDoc}
   *
   * <p>In most cases, subclasses want to call this method first because it may clear all
   * annotations and use the hierarchy's root annotations.
   */
  @Override
  public void postAsMemberOf(AnnotatedTypeMirror type, AnnotatedTypeMirror owner, Element element) {
    super.postAsMemberOf(type, owner, element);

    if (element.getKind().isField()) {
      Collection<? extends AnnotationMirror> declaredFieldAnnotations = getDeclAnnotations(element);
      AnnotatedTypeMirror fieldAnnotations = getAnnotatedType(element);
      computeFieldAccessType(type, declaredFieldAnnotations, owner, fieldAnnotations, element);
    }
  }
  /**
   * Returns a set of triples {@code (expr, (result, annotation))} of conditional postconditions on
   * the method {@code methodElement}.
   */
  public Set<Pair<String, Pair<Boolean, String>>> getConditionalPostconditions(
      ExecutableElement methodElement) {
    Set<Pair<String, Pair<Boolean, String>>> result = new HashSet<>();
    // Check for a single contract.
    AnnotationMirror ensuresAnnotationIf =
        factory.getDeclAnnotation(methodElement, EnsuresQualifierIf.class);
    result.addAll(getConditionalPostcondition(ensuresAnnotationIf));

    // Check for multiple contracts.
    AnnotationMirror ensuresAnnotationsIf =
        factory.getDeclAnnotation(methodElement, EnsuresQualifiersIf.class);
    if (ensuresAnnotationsIf != null) {
      List<AnnotationMirror> annotations =
          AnnotationUtils.getElementValueArray(
              ensuresAnnotationsIf, "value", AnnotationMirror.class, false);
      for (AnnotationMirror a : annotations) {
        result.addAll(getConditionalPostcondition(a));
      }
    }

    // Check type-system specific annotations.
    Class<ConditionalPostconditionAnnotation> metaAnnotation =
        ConditionalPostconditionAnnotation.class;
    List<Pair<AnnotationMirror, AnnotationMirror>> declAnnotations =
        factory.getDeclAnnotationWithMetaAnnotation(methodElement, metaAnnotation);
    for (Pair<AnnotationMirror, AnnotationMirror> r : declAnnotations) {
      AnnotationMirror anno = r.first;
      AnnotationMirror metaAnno = r.second;
      List<String> expressions =
          AnnotationUtils.getElementValueArray(anno, "expression", String.class, false);
      String annotationString =
          AnnotationUtils.getElementValueClassName(metaAnno, "qualifier", false).toString();
      boolean annoResult = AnnotationUtils.getElementValue(anno, "result", Boolean.class, false);
      for (String expr : expressions) {
        result.add(Pair.of(expr, Pair.of(annoResult, annotationString)));
      }
    }
    return result;
  }
  /**
   * Returns a set of pairs {@code (expr, annotation)} of preconditions on the element {@code
   * element}.
   */
  public Set<Pair<String, String>> getPreconditions(Element element) {
    Set<Pair<String, String>> result = new HashSet<>();
    // Check for a single contract.
    AnnotationMirror requiresAnnotation =
        factory.getDeclAnnotation(element, RequiresQualifier.class);
    result.addAll(getPrecondition(requiresAnnotation));

    // Check for multiple contracts.
    AnnotationMirror requiresAnnotations =
        factory.getDeclAnnotation(element, RequiresQualifiers.class);
    if (requiresAnnotations != null) {
      List<AnnotationMirror> annotations =
          AnnotationUtils.getElementValueArray(
              requiresAnnotations, "value", AnnotationMirror.class, false);
      for (AnnotationMirror a : annotations) {
        result.addAll(getPrecondition(a));
      }
    }

    // Check type-system specific annotations.
    Class<PreconditionAnnotation> metaAnnotation = PreconditionAnnotation.class;
    List<Pair<AnnotationMirror, AnnotationMirror>> declAnnotations =
        factory.getDeclAnnotationWithMetaAnnotation(element, metaAnnotation);
    for (Pair<AnnotationMirror, AnnotationMirror> r : declAnnotations) {
      AnnotationMirror anno = r.first;
      AnnotationMirror metaAnno = r.second;
      List<String> expressions =
          AnnotationUtils.getElementValueArray(anno, "value", String.class, false);
      String annotationString =
          AnnotationUtils.getElementValueClassName(metaAnno, "qualifier", false).toString();
      for (String expr : expressions) {
        result.add(Pair.of(expr, annotationString));
      }
    }
    return result;
  }