@Override
  public Void visitBinary(BinaryTree node, Void p) {

    // No checking unless the operator is "==" or "!=".
    if (!(node.getKind() == Tree.Kind.EQUAL_TO || node.getKind() == Tree.Kind.NOT_EQUAL_TO))
      return super.visitBinary(node, p);

    ExpressionTree leftOp = node.getLeftOperand();
    ExpressionTree rightOp = node.getRightOperand();

    // Check passes if either arg is null.
    if (leftOp.getKind() == Tree.Kind.NULL_LITERAL || rightOp.getKind() == Tree.Kind.NULL_LITERAL)
      return super.visitBinary(node, p);

    AnnotatedTypeMirror left = atypeFactory.getAnnotatedType(leftOp);
    AnnotatedTypeMirror right = atypeFactory.getAnnotatedType(rightOp);

    // If either argument is a primitive, check passes due to auto-unboxing
    if (left.getKind().isPrimitive() || right.getKind().isPrimitive())
      return super.visitBinary(node, p);

    if (!(shouldCheckFor(leftOp) && shouldCheckFor(rightOp))) return super.visitBinary(node, p);

    // Syntactic checks for legal uses of ==
    if (suppressInsideComparison(node)) return super.visitBinary(node, p);
    if (suppressEarlyEquals(node)) return super.visitBinary(node, p);
    if (suppressEarlyCompareTo(node)) return super.visitBinary(node, p);

    if (suppressClassAnnotation(left, right)) {
      return super.visitBinary(node, p);
    }

    Element leftElt = null;
    Element rightElt = null;
    if (left
        instanceof org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) {
      leftElt = ((DeclaredType) left.getUnderlyingType()).asElement();
    }
    if (right
        instanceof org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) {
      rightElt = ((DeclaredType) right.getUnderlyingType()).asElement();
    }

    // if neither @Interned or @UsesObjectEquals, report error
    if (!(left.hasEffectiveAnnotation(INTERNED)
        || (leftElt != null && leftElt.getAnnotation(UsesObjectEquals.class) != null)))
      checker.report(Result.failure("not.interned", left), leftOp);
    if (!(right.hasEffectiveAnnotation(INTERNED)
        || (rightElt != null && rightElt.getAnnotation(UsesObjectEquals.class) != null)))
      checker.report(Result.failure("not.interned", right), rightOp);
    return super.visitBinary(node, p);
  }
 protected void reportValidityResult(
     final /*@CompilerMessageKey*/ String errorType,
     final AnnotatedTypeMirror type,
     final Tree p) {
   checker.report(Result.failure(errorType, type.getAnnotations(), type.toString()), p);
   isValid = false;
 }
 @Override
 public Void visitAnnotation(AnnotationTree node, Void p) {
   Element anno = TreeInfo.symbol((JCTree) node.getAnnotationType());
   if (anno.toString().equals(DefaultType.class.getName())) {
     checker.report(Result.failure("annotation.not.allowed.in.src", anno.toString()), node);
   }
   return super.visitAnnotation(node, p);
 }
  /*
   * Method to implement the @UsesObjectEquals functionality.
   * If a class is marked @UsesObjectEquals, it must:
   *
   *    -not override .equals(Object)
   *    -be a subclass of Object or another class marked @UsesObjectEquals
   *
   * If a class is not marked @UsesObjectEquals, it must:
   *
   * 	  -not have a superclass marked @UsesObjectEquals
   *
   *
   * @see org.checkerframework.common.basetype.BaseTypeVisitor#visitClass(com.sun.source.tree.ClassTree, java.lang.Object)
   */
  @Override
  public Void visitClass(ClassTree node, Void p) {
    // Looking for an @UsesObjectEquals class declaration

    TypeElement elt = TreeUtils.elementFromDeclaration(node);
    UsesObjectEquals annotation = elt.getAnnotation(UsesObjectEquals.class);

    Tree superClass = node.getExtendsClause();
    Element elmt = null;
    if (superClass != null
        && (superClass instanceof IdentifierTree || superClass instanceof MemberSelectTree)) {
      elmt = TreeUtils.elementFromUse((ExpressionTree) superClass);
    }

    // if it's there, check to make sure does not override equals
    // and supertype is Object or @UsesObjectEquals
    if (annotation != null) {
      // check methods to ensure no .equals
      if (overridesEquals(node)) {
        checker.report(Result.failure("overrides.equals"), node);
      }

      if (!(superClass == null
          || (elmt != null && elmt.getAnnotation(UsesObjectEquals.class) != null))) {
        checker.report(Result.failure("superclass.unmarked"), node);
      }
    } else {
      // the class is not marked @UsesObjectEquals -> make sure its superclass isn't either.
      // this is impossible after design change making @UsesObjectEquals inherited?
      // check left in case of future design change back to non-inherited.
      if (superClass != null
          && (elmt != null && elmt.getAnnotation(UsesObjectEquals.class) != null)) {
        checker.report(Result.failure("superclass.marked"), node);
      }
    }

    return super.visitClass(node, p);
  }
  @Override
  public Void visitNewArray(NewArrayTree node, Void p) {
    AnnotatedArrayType type = atypeFactory.getAnnotatedType(node);
    AnnotatedTypeMirror componentType = type.getComponentType();
    if (componentType.hasEffectiveAnnotation(NONNULL)
        && !isNewArrayAllZeroDims(node)
        && !isNewArrayInToArray(node)
        && !TypesUtils.isPrimitive(componentType.getUnderlyingType())
        && checker.getLintOption("forbidnonnullarraycomponents", false)) {
      checker.report(
          Result.failure("new.array.type.invalid", componentType.getAnnotations(), type.toString()),
          node);
    }

    return super.visitNewArray(node, p);
  }
 /**
  * Issues a 'dereference.of.nullable' if the type is not of a {@link NonNull} type.
  *
  * @param tree the tree where the error is to reported
  * @param errMsg the error message (must be {@link CompilerMessageKey})
  */
 private void checkForNullability(ExpressionTree tree, /*@CompilerMessageKey*/ String errMsg) {
   AnnotatedTypeMirror type = atypeFactory.getAnnotatedType(tree);
   if (!type.hasEffectiveAnnotation(NONNULL)) {
     checker.report(Result.failure(errMsg, tree), tree);
   }
 }