@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);
  }
  /**
   * Checks that the annotations on the type arguments supplied to a type or a method invocation are
   * within the bounds of the type variables as declared, and issues the
   * "type.argument.type.incompatible" error if they are not.
   *
   * <p>This method used to be visitParameterizedType, which incorrectly handles the main annotation
   * on generic types.
   */
  protected Void visitParameterizedType(AnnotatedDeclaredType type, ParameterizedTypeTree tree) {
    // System.out.printf("TypeValidator.visitParameterizedType: type: %s, tree: %s\n",
    // type, tree);

    if (TreeUtils.isDiamondTree(tree)) return null;

    final TypeElement element = (TypeElement) type.getUnderlyingType().asElement();
    if (checker.shouldSkipUses(element)) return null;

    List<AnnotatedTypeVariable> typevars = atypeFactory.typeVariablesFromUse(type, element);

    visitor.checkTypeArguments(tree, typevars, type.getTypeArguments(), tree.getTypeArguments());

    return null;
  }
  @Override
  public Void visitDeclared(AnnotatedDeclaredType type, Tree tree) {
    if (checker.shouldSkipUses(type.getUnderlyingType().asElement()))
      return super.visitDeclared(type, tree);

    {
      // Ensure that type use is a subtype of the element type
      // isValidUse determines the erasure of the types.
      AnnotatedDeclaredType elemType =
          (AnnotatedDeclaredType)
              atypeFactory.getAnnotatedType(type.getUnderlyingType().asElement());

      if (!visitor.isValidUse(elemType, type, tree)) {
        reportError(type, tree);
      }
    }

    // System.out.println("Type: " + type);
    // System.out.println("Tree: " + tree);
    // System.out.println("Tree kind: " + tree.getKind());

    /*
     * Try to reconstruct the ParameterizedTypeTree from the given tree.
     * TODO: there has to be a nicer way to do this...
     */
    Pair<ParameterizedTypeTree, AnnotatedDeclaredType> p = extractParameterizedTypeTree(tree, type);
    ParameterizedTypeTree typeargtree = p.first;
    type = p.second;

    if (typeargtree != null) {
      // We have a ParameterizedTypeTree -> visit it.

      visitParameterizedType(type, typeargtree);

      /*
       * Instead of calling super with the unchanged "tree", adapt the
       * second argument to be the corresponding type argument tree. This
       * ensures that the first and second parameter to this method always
       * correspond. visitDeclared is the only method that had this
       * problem.
       */
      List<? extends AnnotatedTypeMirror> tatypes = type.getTypeArguments();

      if (tatypes == null) return null;

      // May be zero for a "diamond" (inferred type args in constructor
      // invocation).
      int numTypeArgs = typeargtree.getTypeArguments().size();
      if (numTypeArgs != 0) {
        // TODO: this should be an equality, but in
        // http://buffalo.cs.washington.edu:8080/job/jdk6-daikon-typecheck/2061/console
        // it failed with:
        // daikon/Debug.java; message: size mismatch for type arguments:
        // @NonNull Object and Class<?>
        // but I didn't manage to reduce it to a test case.
        assert tatypes.size() <= numTypeArgs
            : "size mismatch for type arguments: " + type + " and " + typeargtree;

        for (int i = 0; i < tatypes.size(); ++i) {
          scan(tatypes.get(i), typeargtree.getTypeArguments().get(i));
        }
      }

      return null;

      // Don't call the super version, because it creates a mismatch
      // between
      // the first and second parameters.
      // return super.visitDeclared(type, tree);
    }

    return super.visitDeclared(type, tree);
  }
  @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);
  }
  private Pair<ParameterizedTypeTree, AnnotatedDeclaredType> extractParameterizedTypeTree(
      Tree tree, AnnotatedDeclaredType type) {
    ParameterizedTypeTree typeargtree = null;

    switch (tree.getKind()) {
      case VARIABLE:
        Tree lt = ((VariableTree) tree).getType();
        if (lt instanceof ParameterizedTypeTree) {
          typeargtree = (ParameterizedTypeTree) lt;
        } else {
          // System.out.println("Found a: " + lt);
        }
        break;
      case PARAMETERIZED_TYPE:
        typeargtree = (ParameterizedTypeTree) tree;
        break;
      case NEW_CLASS:
        NewClassTree nct = (NewClassTree) tree;
        ExpressionTree nctid = nct.getIdentifier();
        if (nctid.getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
          typeargtree = (ParameterizedTypeTree) nctid;
          /*
           * This is quite tricky... for anonymous class instantiations,
           * the type at this point has no type arguments. By doing the
           * following, we get the type arguments again.
           */
          type = (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(typeargtree);
        }
        break;
      case ANNOTATED_TYPE:
        AnnotatedTypeTree tr = (AnnotatedTypeTree) tree;
        ExpressionTree undtr = tr.getUnderlyingType();
        if (undtr instanceof ParameterizedTypeTree) {
          typeargtree = (ParameterizedTypeTree) undtr;
        } else if (undtr instanceof IdentifierTree) {
          // @Something D -> Nothing to do
        } else {
          // TODO: add more test cases to ensure that nested types are
          // handled correctly,
          // e.g. @Nullable() List<@Nullable Object>[][]
          Pair<ParameterizedTypeTree, AnnotatedDeclaredType> p =
              extractParameterizedTypeTree(undtr, type);
          typeargtree = p.first;
          type = p.second;
        }
        break;
      case IDENTIFIER:
      case ARRAY_TYPE:
      case NEW_ARRAY:
      case MEMBER_SELECT:
      case UNBOUNDED_WILDCARD:
      case EXTENDS_WILDCARD:
      case SUPER_WILDCARD:
      case TYPE_PARAMETER:
        // Nothing to do.
        // System.out.println("Found a: " + (tree instanceof
        // ParameterizedTypeTree));
        break;
      default:
        // the parameterized type is the result of some expression tree.
        // No need to do anything further.
        break;
        // System.err.printf("TypeValidator.visitDeclared unhandled tree: %s of kind %s\n",
        //                 tree, tree.getKind());
    }

    return Pair.of(typeargtree, type);
  }
  /**
   * Get the type of element from the realTypeFactory. Copy it's annotations to inferenceType. Add
   * a @VarAnnot to all definite type use locations (locations that can be defaulted) in
   * inferenceType and add an equality constraint between it and the "real" annotations
   *
   * @param element The bytecode declaration from which inferenceType was created
   * @param inferenceType The type of element. inferenceType will be annotated by this method
   */
  public void annotate(final Element element, final AnnotatedTypeMirror inferenceType) {
    final AnnotatedTypeMirror realType = realTypeFactory.getAnnotatedType(element);

    CopyUtil.copyAnnotations(realType, inferenceType);
    inferenceTypeFactory.getNewConstantToVariableAnnotator().visit(inferenceType);
  }