Search in sources :

Example 1 with Nullness

use of com.google.errorprone.dataflow.nullnesspropagation.Nullness in project error-prone by google.

the class FieldMissingNullable method matchAssignment.

@Override
public Description matchAssignment(AssignmentTree tree, VisitorState state) {
    Symbol assigned = ASTHelpers.getSymbol(tree.getVariable());
    if (assigned == null || assigned.getKind() != ElementKind.FIELD || assigned.type.isPrimitive()) {
        // not a field of nullable type
        return Description.NO_MATCH;
    }
    // Best-effort try to avoid running the dataflow analysis
    // TODO(kmb): bail on more non-null expressions, such as "this", arithmethic, logical, and &&/||
    ExpressionTree expression = tree.getExpression();
    if (ASTHelpers.constValue(expression) != null) {
        // This should include literals such as "true" or a string
        return Description.NO_MATCH;
    }
    if (TrustingNullnessAnalysis.hasNullableAnnotation(assigned)) {
        // field already annotated
        return Description.NO_MATCH;
    }
    VariableTree fieldDecl = findDeclaration(state, assigned);
    if (fieldDecl == null) {
        // skip fields declared elsewhere for simplicity
        return Description.NO_MATCH;
    }
    // Don't need dataflow to tell us that null is nullable
    if (expression.getKind() == Tree.Kind.NULL_LITERAL) {
        return makeFix(fieldDecl, tree, "Assigning null literal to field");
    }
    // OK let's see what dataflow says
    Nullness nullness = TrustingNullnessAnalysis.instance(state.context).getNullness(new TreePath(state.getPath(), expression), state.context);
    if (nullness == null) {
        // TODO(kmb): Make dataflow work for lambda expressions
        return Description.NO_MATCH;
    }
    switch(nullness) {
        case BOTTOM:
        case NONNULL:
            return Description.NO_MATCH;
        case NULL:
            return makeFix(fieldDecl, tree, "Assigning null to field");
        case NULLABLE:
            return makeFix(fieldDecl, tree, "May assign null to field");
        default:
            throw new AssertionError("Impossible: " + nullness);
    }
}
Also used : TreePath(com.sun.source.util.TreePath) Symbol(com.sun.tools.javac.code.Symbol) VariableTree(com.sun.source.tree.VariableTree) ExpressionTree(com.sun.source.tree.ExpressionTree) Nullness(com.google.errorprone.dataflow.nullnesspropagation.Nullness)

Example 2 with Nullness

use of com.google.errorprone.dataflow.nullnesspropagation.Nullness in project error-prone by google.

the class FieldMissingNullable method matchVariable.

@Override
public Description matchVariable(VariableTree tree, VisitorState state) {
    Symbol assigned = ASTHelpers.getSymbol(tree);
    if (assigned == null || assigned.getKind() != ElementKind.FIELD || assigned.type.isPrimitive()) {
        // not a field of nullable type
        return Description.NO_MATCH;
    }
    ExpressionTree expression = tree.getInitializer();
    if (expression == null || ASTHelpers.constValue(expression) != null) {
        // This should include literals such as "true" or a string
        return Description.NO_MATCH;
    }
    if (TrustingNullnessAnalysis.hasNullableAnnotation(assigned)) {
        // field already annotated
        return Description.NO_MATCH;
    }
    // Don't need dataflow to tell us that null is nullable
    if (expression.getKind() == Tree.Kind.NULL_LITERAL) {
        return makeFix(tree, tree, "Initializing field with null literal");
    }
    // OK let's see what dataflow says
    // TODO(kmb): Merge this method with matchAssignment once we unify nullness analysis entry point
    Nullness nullness = TrustingNullnessAnalysis.instance(state.context).getFieldInitializerNullness(state.getPath(), state.context);
    switch(nullness) {
        case BOTTOM:
        case NONNULL:
            return Description.NO_MATCH;
        case NULL:
            return makeFix(tree, tree, "Initializing field with null");
        case NULLABLE:
            return makeFix(tree, tree, "May initialize field with null");
        default:
            throw new AssertionError("Impossible: " + nullness);
    }
}
Also used : Symbol(com.sun.tools.javac.code.Symbol) ExpressionTree(com.sun.source.tree.ExpressionTree) Nullness(com.google.errorprone.dataflow.nullnesspropagation.Nullness)

Example 3 with Nullness

use of com.google.errorprone.dataflow.nullnesspropagation.Nullness in project error-prone by google.

the class ParameterNotNullable method matchDereference.

private Description matchDereference(ExpressionTree dereferencedExpression, VisitorState state) {
    Symbol dereferenced = ASTHelpers.getSymbol(dereferencedExpression);
    if (dereferenced == null || dereferenced.getKind() != ElementKind.PARAMETER || dereferenced.type.isPrimitive()) {
        // not a parameter dereference
        return Description.NO_MATCH;
    }
    if (!TrustingNullnessAnalysis.hasNullableAnnotation(dereferenced)) {
        return Description.NO_MATCH;
    }
    Nullness nullness = TrustingNullnessAnalysis.instance(state.context).getNullness(new TreePath(state.getPath(), dereferencedExpression), state.context);
    if (nullness != Nullness.NULLABLE) {
        return Description.NO_MATCH;
    }
    for (AnnotationTree anno : findDeclaration(state, dereferenced).getModifiers().getAnnotations()) {
        if (ASTHelpers.getSymbol(anno).type.toString().endsWith(".Nullable")) {
            return buildDescription(dereferencedExpression).setMessage("Nullable parameter not checked for null").addFix(SuggestedFix.delete(anno)).build();
        }
    }
    // Shouldn't get here
    return Description.NO_MATCH;
}
Also used : TreePath(com.sun.source.util.TreePath) Symbol(com.sun.tools.javac.code.Symbol) AnnotationTree(com.sun.source.tree.AnnotationTree) Nullness(com.google.errorprone.dataflow.nullnesspropagation.Nullness)

Example 4 with Nullness

use of com.google.errorprone.dataflow.nullnesspropagation.Nullness in project error-prone by google.

the class AbstractReferenceEquality method addFixes.

protected void addFixes(Description.Builder builder, BinaryTree tree, VisitorState state) {
    ExpressionTree lhs = tree.getLeftOperand();
    ExpressionTree rhs = tree.getRightOperand();
    Optional<Fix> fixToReplaceOrStatement = inOrStatementWithEqualsCheck(state, tree);
    if (fixToReplaceOrStatement.isPresent()) {
        builder.addFix(fixToReplaceOrStatement.get());
        return;
    }
    // Swap the order (e.g. rhs.equals(lhs) if the rhs is a non-null constant, and the lhs is not
    if (ASTHelpers.constValue(lhs) == null && ASTHelpers.constValue(rhs) != null) {
        ExpressionTree tmp = lhs;
        lhs = rhs;
        rhs = tmp;
    }
    String prefix = tree.getKind() == Kind.NOT_EQUAL_TO ? "!" : "";
    String lhsSource = state.getSourceForNode(lhs);
    String rhsSource = state.getSourceForNode(rhs);
    Nullness nullness = getNullness(lhs, state);
    // If the lhs is possibly-null, provide both options.
    if (nullness != NONNULL) {
        builder.addFix(SuggestedFix.builder().replace(tree, String.format("%sObjects.equals(%s, %s)", prefix, lhsSource, rhsSource)).addImport("java.util.Objects").build());
    }
    if (nullness != NULL) {
        builder.addFix(SuggestedFix.replace(tree, String.format("%s%s.equals(%s)", prefix, lhs instanceof BinaryTree ? String.format("(%s)", lhsSource) : lhsSource, rhsSource)));
    }
}
Also used : SuggestedFix(com.google.errorprone.fixes.SuggestedFix) Fix(com.google.errorprone.fixes.Fix) BinaryTree(com.sun.source.tree.BinaryTree) ExpressionTree(com.sun.source.tree.ExpressionTree) Nullness(com.google.errorprone.dataflow.nullnesspropagation.Nullness)

Example 5 with Nullness

use of com.google.errorprone.dataflow.nullnesspropagation.Nullness in project error-prone by google.

the class ReturnMissingNullable method matchReturn.

@Override
public Description matchReturn(ReturnTree tree, VisitorState state) {
    ExpressionTree returnExpression = tree.getExpression();
    if (returnExpression == null) {
        return Description.NO_MATCH;
    }
    // TODO(kmb): bail on more non-null expressions, such as "this", arithmethic, logical, and &&/||
    if (ASTHelpers.constValue(returnExpression) != null) {
        // This should include literals such as "true" or a string
        return Description.NO_MATCH;
    }
    JCMethodDecl method = findSurroundingMethod(state.getPath());
    if (method == null || isIgnoredReturnType(method, state)) {
        return Description.NO_MATCH;
    }
    if (TrustingNullnessAnalysis.hasNullableAnnotation(method.sym)) {
        return Description.NO_MATCH;
    }
    // Don't need dataflow to tell us that null is nullable
    if (returnExpression.getKind() == ExpressionTree.Kind.NULL_LITERAL) {
        return makeFix(method, tree, "Returning null literal");
    }
    // OK let's see what dataflow says
    Nullness nullness = TrustingNullnessAnalysis.instance(state.context).getNullness(new TreePath(state.getPath(), returnExpression), state.context);
    switch(nullness) {
        case BOTTOM:
        case NONNULL:
            return Description.NO_MATCH;
        case NULL:
            return makeFix(method, tree, "Definitely returning null");
        case NULLABLE:
            return makeFix(method, tree, "May return null");
        default:
            throw new AssertionError("Impossible: " + nullness);
    }
}
Also used : JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) TreePath(com.sun.source.util.TreePath) ExpressionTree(com.sun.source.tree.ExpressionTree) Nullness(com.google.errorprone.dataflow.nullnesspropagation.Nullness)

Aggregations

Nullness (com.google.errorprone.dataflow.nullnesspropagation.Nullness)5 ExpressionTree (com.sun.source.tree.ExpressionTree)4 TreePath (com.sun.source.util.TreePath)3 Symbol (com.sun.tools.javac.code.Symbol)3 Fix (com.google.errorprone.fixes.Fix)1 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)1 AnnotationTree (com.sun.source.tree.AnnotationTree)1 BinaryTree (com.sun.source.tree.BinaryTree)1 VariableTree (com.sun.source.tree.VariableTree)1 JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)1