@Override public Void visitNewClass(NewClassTree node, Void p) { AnnotatedDeclaredType type = atypeFactory.getAnnotatedType(node); ExpressionTree identifier = node.getIdentifier(); if (identifier instanceof AnnotatedTypeTree) { AnnotatedTypeTree t = (AnnotatedTypeTree) identifier; for (AnnotationMirror a : atypeFactory.getAnnotatedType(t).getAnnotations()) { // is this an annotation of the nullness checker? boolean nullnessCheckerAnno = containsSameIgnoringValues(atypeFactory.getNullnessAnnotations(), a); if (nullnessCheckerAnno && !AnnotationUtils.areSame(NONNULL, a)) { // The type is not non-null => warning checker.report(Result.warning("new.class.type.invalid", type.getAnnotations()), node); // Note that other consistency checks are made by isValid. } } if (t.toString().contains("@PolyNull")) { // TODO: this is a hack, but PolyNull gets substituted // afterwards checker.report(Result.warning("new.class.type.invalid", type.getAnnotations()), node); } } // TODO: It might be nicer to introduce a framework-level // isValidNewClassType or some such. return super.visitNewClass(node, p); }
@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); }
/** * Reports an error if a comparison of a @NonNull expression with the null literal is performed. */ protected void checkForRedundantTests(BinaryTree node) { final ExpressionTree leftOp = node.getLeftOperand(); final ExpressionTree rightOp = node.getRightOperand(); // respect command-line option if (!checker.getLintOption( AbstractNullnessChecker.LINT_REDUNDANTNULLCOMPARISON, AbstractNullnessChecker.LINT_DEFAULT_REDUNDANTNULLCOMPARISON)) { return; } // equality tests if ((node.getKind() == Tree.Kind.EQUAL_TO || node.getKind() == Tree.Kind.NOT_EQUAL_TO)) { AnnotatedTypeMirror left = atypeFactory.getAnnotatedType(leftOp); AnnotatedTypeMirror right = atypeFactory.getAnnotatedType(rightOp); if (leftOp.getKind() == Tree.Kind.NULL_LITERAL && right.hasEffectiveAnnotation(NONNULL)) checker.report(Result.warning(KNOWN_NONNULL, rightOp.toString()), node); else if (rightOp.getKind() == Tree.Kind.NULL_LITERAL && left.hasEffectiveAnnotation(NONNULL)) checker.report(Result.warning(KNOWN_NONNULL, leftOp.toString()), node); } }
/* * 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 visitMethodInvocation(MethodInvocationTree node, Void p) { if (isInvocationOfEquals(node)) { AnnotatedTypeMirror recv = atypeFactory.getReceiverType(node); AnnotatedTypeMirror comp = atypeFactory.getAnnotatedType(node.getArguments().get(0)); if (this.checker.getLintOption("dotequals", true) && recv.hasEffectiveAnnotation(INTERNED) && comp.hasEffectiveAnnotation(INTERNED)) checker.report(Result.warning("unnecessary.equals"), node); } return super.visitMethodInvocation(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); } }