/** @inheritDoc */
  @Override
  public VariableSlot getVariableSlot(final AnnotatedTypeMirror atm) {

    AnnotationMirror annot = atm.getAnnotationInHierarchy(this.varAnnot);
    if (annot == null) {
      annot = atm.getAnnotationInHierarchy(this.unqualified);
      if (annot == null) {
        if (InferenceMain.isHackMode()) {
          return null;
        }

        ErrorReporter.errorAbort("Missing VarAnnot annotation: " + atm);
      }
    }

    return (VariableSlot) getSlot(annot);
  }
  @Override
  public Void visitWildcard(AnnotatedWildcardType type, Tree tree) {
    if (visitedNodes.containsKey(type)) {
      return visitedNodes.get(type);
    }

    // Keep in sync with visitTypeVariable
    Set<AnnotationMirror> onVar = type.getAnnotations();
    if (!onVar.isEmpty()) {
      // System.out.printf("BaseTypeVisitor.TypeValidator.visitWildcard(type: %s, tree: %s)",
      // type, tree);

      // TODO: the following check should not be necessary, once we are
      // able to
      // recurse on type parameters in AnnotatedTypes.isValidType (see
      // todo there).
      {
        // Check whether multiple qualifiers from the same hierarchy
        // appear.
        Set<AnnotationMirror> seenTops = AnnotationUtils.createAnnotationSet();
        for (AnnotationMirror aOnVar : onVar) {
          AnnotationMirror top = atypeFactory.getQualifierHierarchy().getTopAnnotation(aOnVar);
          if (seenTops.contains(top)) {
            this.reportError(type, tree);
          }
          seenTops.add(top);
        }
      }

      /* TODO: see note with visitTypeVariable
      if (type.getExtendsBoundField() != null) {
          AnnotatedTypeMirror upper = type.getExtendsBoundField();
          for (AnnotationMirror aOnVar : onVar) {
              if (upper.isAnnotatedInHierarchy(aOnVar) &&
                      !atypeFactory.getQualifierHierarchy().isSubtype(aOnVar,
                              upper.getAnnotationInHierarchy(aOnVar))) {
                  this.reportError(type, tree);
              }
          }
          upper.replaceAnnotations(onVar);
      }
      */

      if (type.getSuperBoundField() != null) {
        AnnotatedTypeMirror lower = type.getSuperBoundField();
        for (AnnotationMirror aOnVar : onVar) {
          if (lower.isAnnotatedInHierarchy(aOnVar)
              && !atypeFactory
                  .getQualifierHierarchy()
                  .isSubtype(lower.getAnnotationInHierarchy(aOnVar), aOnVar)) {
            this.reportError(type, tree);
          }
        }
        lower.replaceAnnotations(onVar);
      }
    }
    return super.visitWildcard(type, tree);
  }
 private List<?> getValues(AnnotatedTypeMirror type, TypeMirror castTo) {
   AnnotationMirror anno = type.getAnnotationInHierarchy(UNKNOWNVAL);
   if (anno == null) {
     // if type is an AnnotatedTypeVariable (or other type without a primary annotation)
     // then anno will be null. It would be safe to use the annotation on the upper bound;
     //  however, unless the upper bound was explicitly annotated, it will be unknown.
     // AnnotatedTypes.findEffectiveAnnotationInHierarchy(, toSearch, top)
     return new ArrayList<>();
   }
   return ValueCheckerUtils.getValuesCastedToType(anno, castTo);
 }
    /**
     * If any constant-value annotation has &gt; MAX_VALUES number of values provided, treats the
     * value as UnknownVal. Works together with ValueVisitor.visitAnnotation, which issues a warning
     * to the user in this case.
     */
    private void replaceWithUnknownValIfTooManyValues(AnnotatedTypeMirror atm) {
      AnnotationMirror anno = atm.getAnnotationInHierarchy(UNKNOWNVAL);

      if (anno != null && anno.getElementValues().size() > 0) {
        List<Object> values =
            AnnotationUtils.getElementValueArray(anno, "value", Object.class, false);
        if (values != null && values.size() > MAX_VALUES) {
          atm.replaceAnnotation(UNKNOWNVAL);
        }
      }
    }
  @Override
  public Void visitTypeVariable(AnnotatedTypeVariable type, Tree tree) {
    if (visitedNodes.containsKey(type)) {
      return visitedNodes.get(type);
    }

    // Keep in sync with visitWildcard
    Set<AnnotationMirror> onVar = type.getAnnotations();
    if (!onVar.isEmpty()) {
      // System.out.printf("BaseTypeVisitor.TypeValidator.visitTypeVariable(type: %s, tree: %s)%n",
      // type, tree);

      // TODO: the following check should not be necessary, once we are
      // able to
      // recurse on type parameters in AnnotatedTypes.isValidType (see
      // todo there).
      {
        // Check whether multiple qualifiers from the same hierarchy
        // appear.
        Set<AnnotationMirror> seenTops = AnnotationUtils.createAnnotationSet();
        for (AnnotationMirror aOnVar : onVar) {
          AnnotationMirror top = atypeFactory.getQualifierHierarchy().getTopAnnotation(aOnVar);
          if (seenTops.contains(top)) {
            this.reportError(type, tree);
          }
          seenTops.add(top);
        }
      }

      // TODO: because of the way AnnotatedTypeMirror fixes up the bounds,
      // i.e. an annotation on the type variable always replaces a
      // corresponding
      // annotation in the bound, some of these checks are not actually
      // meaningful.
      /*if (type.getUpperBoundField() != null) {
          AnnotatedTypeMirror upper = type.getUpperBoundField();

          for (AnnotationMirror aOnVar : onVar) {
              if (upper.isAnnotatedInHierarchy(aOnVar) &&
                      !checker.getQualifierHierarchy().isSubtype(aOnVar,
                              upper.getAnnotationInHierarchy(aOnVar))) {
                  this.reportError(type, tree);
              }
          }
          upper.replaceAnnotations(onVar);
      }*/

      if (type.getLowerBoundField() != null) {
        AnnotatedTypeMirror lower = type.getLowerBoundField();
        for (AnnotationMirror aOnVar : onVar) {
          if (lower.isAnnotatedInHierarchy(aOnVar)
              && !atypeFactory
                  .getQualifierHierarchy()
                  .isSubtype(lower.getAnnotationInHierarchy(aOnVar), aOnVar)) {
            this.reportError(type, tree);
          }
        }
        lower.replaceAnnotations(onVar);
      }
    }

    return super.visitTypeVariable(type, tree);
  }