diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/BigDecimalLiteralDouble.java b/core/src/main/java/com/google/errorprone/bugpatterns/BigDecimalLiteralDouble.java index 2ba797bd3ec..ce24e0c22fa 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/BigDecimalLiteralDouble.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/BigDecimalLiteralDouble.java @@ -27,6 +27,8 @@ import com.google.errorprone.matchers.Matcher; import com.google.errorprone.matchers.Matchers; import com.google.errorprone.util.ASTHelpers; +import com.sun.tools.javac.code.Type; +import javax.lang.model.type.TypeKind; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.NewClassTree; import com.sun.source.tree.Tree.Kind; @@ -54,12 +56,27 @@ public class BigDecimalLiteralDouble extends BugChecker implements NewClassTreeM // Matches literals and unary +/- followed by a literal, since most people conceptually think of // -1.0 as a literal. Doesn't handle nested unary operators as new BigDecimal(String) doesn't // accept multiple unary prefixes. - private static boolean floatingPointArgument(ExpressionTree tree) { - if (tree.getKind() == Kind.UNARY_PLUS || tree.getKind() == Kind.UNARY_MINUS) { - tree = ((UnaryTree) tree).getExpression(); - } - return tree.getKind() == Kind.DOUBLE_LITERAL || tree.getKind() == Kind.FLOAT_LITERAL; - } + private static boolean floatingPointArgument(ExpressionTree tree, VisitorState state) { + if (tree.getKind() == Kind.UNARY_PLUS || tree.getKind() == Kind.UNARY_MINUS) { + tree = ((UnaryTree) tree).getExpression(); + } + + if (tree.getKind() == Kind.DOUBLE_LITERAL || tree.getKind() == Kind.FLOAT_LITERAL) { + return true; + } + + Type type = ASTHelpers.getType(tree); + if (type == null) { + return false; + } + + if (type.getKind() == TypeKind.DOUBLE || type.getKind() == TypeKind.FLOAT) { + return true; + } + + return ASTHelpers.isSameType(type, state.getTypeFromString("java.lang.Double"), state) + || ASTHelpers.isSameType(type, state.getTypeFromString("java.lang.Float"), state); + } @Override public Description matchNewClass(NewClassTree tree, VisitorState state) { @@ -68,11 +85,19 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { } ExpressionTree arg = getOnlyElement(tree.getArguments()); - if (!floatingPointArgument(arg)) { + + if (!floatingPointArgument(arg, state)) { return Description.NO_MATCH; } - return createDescription(arg, state); + if (arg.getKind() == Kind.DOUBLE_LITERAL + || arg.getKind() == Kind.FLOAT_LITERAL + || arg.getKind() == Kind.UNARY_PLUS + || arg.getKind() == Kind.UNARY_MINUS) { + return createDescription(arg, state); + } + + return buildDescription(arg).build(); } private Description createDescription(ExpressionTree arg, VisitorState state) { diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/BigDecimalLiteralDoubleTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/BigDecimalLiteralDoubleTest.java index ff6ade36c22..06c5daafaaa 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/BigDecimalLiteralDoubleTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/BigDecimalLiteralDoubleTest.java @@ -90,4 +90,30 @@ void test() { && message.contains("new BigDecimal(\"0.99\")")) .doTest(); } + + @Test + public void losesPrecision_boxedFloatingPoint() { + compilationHelper + .addSourceLines( + "Test.java", + """ + import java.math.BigDecimal; + + class Test { + void test() { + Double boxedD = 0.1; + // BUG: Diagnostic contains: new BigDecimal(double) loses precision + new BigDecimal(boxedD); + + Float boxedF = 0.1f; + // BUG: Diagnostic contains: new BigDecimal(double) loses precision + new BigDecimal(boxedF); + + // BUG: Diagnostic contains: new BigDecimal(double) loses precision + new BigDecimal((Float) 0.3f); + } + } + """) + .doTest(); + } }