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);
}
}
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);
}
}
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;
}
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)));
}
}
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);
}
}
Aggregations