use of com.sun.source.tree.ExpressionTree 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);
}
}
use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class ProvidesNull method matchReturn.
/**
* Matches explicit "return null" statements in methods annotated with {@code @Provides} but not
* {@code @Nullable}. Suggests either annotating the method with {@code @Nullable} or throwing a
* {@link RuntimeException} instead.
*/
// TODO(eaftan): Use nullness dataflow analysis when it's ready
@Override
public Description matchReturn(ReturnTree returnTree, VisitorState state) {
ExpressionTree returnExpression = returnTree.getExpression();
if (returnExpression == null || returnExpression.getKind() != Kind.NULL_LITERAL) {
return Description.NO_MATCH;
}
TreePath path = state.getPath();
MethodTree enclosingMethod = null;
while (true) {
if (path == null || path.getLeaf() instanceof LambdaExpressionTree) {
return Description.NO_MATCH;
} else if (path.getLeaf() instanceof MethodTree) {
enclosingMethod = (MethodTree) path.getLeaf();
break;
} else {
path = path.getParentPath();
}
}
MethodSymbol enclosingMethodSym = ASTHelpers.getSymbol(enclosingMethod);
if (enclosingMethodSym == null) {
return Description.NO_MATCH;
}
if (!ASTHelpers.hasAnnotation(enclosingMethodSym, "dagger.Provides", state) || ASTHelpers.hasDirectAnnotationWithSimpleName(enclosingMethodSym, "Nullable")) {
return Description.NO_MATCH;
}
Fix addNullableFix = SuggestedFix.builder().prefixWith(enclosingMethod, "@Nullable\n").addImport("javax.annotation.Nullable").build();
CatchTree enclosingCatch = ASTHelpers.findEnclosingNode(state.getPath(), CatchTree.class);
if (enclosingCatch == null) {
// If not in a catch block, suggest adding @Nullable first, then throwing an exception.
Fix throwRuntimeExceptionFix = SuggestedFix.replace(returnTree, "throw new RuntimeException();");
return buildDescription(returnTree).addFix(addNullableFix).addFix(throwRuntimeExceptionFix).build();
} else {
// If in a catch block, suggest throwing an exception first, then adding @Nullable.
String replacement = String.format("throw new RuntimeException(%s);", enclosingCatch.getParameter().getName());
Fix throwRuntimeExceptionFix = SuggestedFix.replace(returnTree, replacement);
return buildDescription(returnTree).addFix(throwRuntimeExceptionFix).addFix(addNullableFix).build();
}
}
use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class DoubleCheckedLocking method getNullCheckedExpression.
/**
* Matches comparisons to null (e.g. {@code foo == null}) and returns the expression being
* tested.
*/
private static ExpressionTree getNullCheckedExpression(ExpressionTree condition) {
condition = TreeInfo.skipParens((JCExpression) condition);
if (!(condition instanceof BinaryTree)) {
return null;
}
BinaryTree bin = (BinaryTree) condition;
ExpressionTree other;
if (bin.getLeftOperand().getKind() == Kind.NULL_LITERAL) {
other = bin.getRightOperand();
} else if (bin.getRightOperand().getKind() == Kind.NULL_LITERAL) {
other = bin.getLeftOperand();
} else {
return null;
}
return other;
}
use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class DoubleCheckedLocking method findDCL.
/**
* Matches an instance of DCL. The canonical pattern is:
*
* <pre>
* {@code
* if ($X == null) {
* synchronized (...) {
* if ($X == null) {
* ...
* }
* ...
* }
* }
* }
* </pre>
*
* Gaps before the synchronized or inner 'if' statement are ignored, and the operands in the
* null-checks are accepted in either order.
*/
@Nullable
static DCLInfo findDCL(IfTree outerIf) {
// TODO(cushon): Optional.ifPresent...
ExpressionTree outerIfTest = getNullCheckedExpression(outerIf.getCondition());
if (outerIfTest == null) {
return null;
}
SynchronizedTree synchTree = getChild(outerIf.getThenStatement(), SynchronizedTree.class);
if (synchTree == null) {
return null;
}
IfTree innerIf = getChild(synchTree.getBlock(), IfTree.class);
if (innerIf == null) {
return null;
}
ExpressionTree innerIfTest = getNullCheckedExpression(innerIf.getCondition());
if (innerIfTest == null) {
return null;
}
Symbol outerSym = ASTHelpers.getSymbol(outerIfTest);
if (!Objects.equals(outerSym, ASTHelpers.getSymbol(innerIfTest))) {
return null;
}
if (!(outerSym instanceof VarSymbol)) {
return null;
}
VarSymbol var = (VarSymbol) outerSym;
return DCLInfo.create(outerIf, synchTree, innerIf, var);
}
use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class ProtoFieldNullComparison method getMethodName.
private static String getMethodName(ExpressionTree tree) {
MethodInvocationTree method = (MethodInvocationTree) tree;
ExpressionTree expressionTree = method.getMethodSelect();
JCFieldAccess access = (JCFieldAccess) expressionTree;
return access.sym.getQualifiedName().toString();
}
Aggregations