--- java.hints/src/org/netbeans/modules/java/hints/suggestions/UseBDConstFix.java +++ java.hints/src/org/netbeans/modules/java/hints/suggestions/UseBDConstFix.java @@ -0,0 +1,135 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.modules.java.hints.suggestions; + +import com.sun.source.tree.LiteralTree; +import com.sun.source.tree.Tree; +import com.sun.source.util.TreePath; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Arrays; +import javax.lang.model.SourceVersion; +import org.netbeans.modules.java.hints.ArithmeticUtilities; +import org.netbeans.spi.editor.hints.ErrorDescription; +import org.netbeans.spi.editor.hints.Fix; +import org.netbeans.spi.editor.hints.Severity; +import org.netbeans.spi.java.hints.ErrorDescriptionFactory; +import org.netbeans.spi.java.hints.Hint; +import org.netbeans.spi.java.hints.HintContext; +import org.netbeans.spi.java.hints.TriggerPattern; +import org.netbeans.spi.java.hints.TriggerPatterns; +import org.openide.util.NbBundle.Messages; + +@Messages({ + "# {0} - f.e. BigDecimal.ONE", + "ERR_UseBDConstFix=Replace with {0}", + "DN_UseBigDecimalConstants=Use BigDecimal constants where possible", + "DESC_UseBigDecimalConstants=Introduces BigDecimal constants where possible.

For example: new java.math.BigDecimal(1.0) will be replaced by BigDecimal.ONE

",}) +/** + * @author markiewb + */ +public class UseBDConstFix { + + @Hint(displayName = "#DN_UseBigDecimalConstants", description = "#DESC_UseBigDecimalConstants", category = "rules15", hintKind = Hint.Kind.INSPECTION, severity = Severity.HINT) + @TriggerPatterns( + { + @TriggerPattern("new java.math.BigDecimal($v)"), + @TriggerPattern("java.math.BigDecimal.valueOf($v)"), + } + ) + public static ErrorDescription convert(HintContext ctx) { + if (!isAtLeastJDK5(ctx)) { + return null; + } + + TreePath get = ctx.getVariables().get("$v"); + if (null == get) { + return null; + } + + String literal = getLiteralValue(get); + + BigDecimal valueOf = getArithmeticValue(ctx, get); + Fix fix = null; + if (equals(valueOf, BigDecimal.ONE) || contains(literal, "1", "1.0", "1.00")) { + fix = org.netbeans.spi.java.hints.JavaFixUtilities.rewriteFix(ctx, Bundle.ERR_UseBDConstFix("BigDecimal.ONE"), ctx.getPath(), "java.math.BigDecimal.ONE"); + } + if (equals(valueOf, BigDecimal.ZERO) || contains(literal, "0", "0.0", "0.00")) { + fix = org.netbeans.spi.java.hints.JavaFixUtilities.rewriteFix(ctx, Bundle.ERR_UseBDConstFix("BigDecimal.ZERO"), ctx.getPath(), "java.math.BigDecimal.ZERO"); + } + if (equals(valueOf, BigDecimal.TEN) || contains(literal, "10", "10.0", "10.00")) { + fix = org.netbeans.spi.java.hints.JavaFixUtilities.rewriteFix(ctx, Bundle.ERR_UseBDConstFix("BigDecimal.TEN"), ctx.getPath(), "java.math.BigDecimal.TEN"); + } + if (null != fix) { + return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), Bundle.DN_UseBigDecimalConstants(), fix); + } + return null; + } + + private static boolean contains(String literal, String... patterns) { + return Arrays.asList(patterns).contains(literal); + } + + private static boolean equals(BigDecimal valueOf, final BigDecimal ONE) { + return valueOf != null && ONE.compareTo(valueOf) == 0; + } + + private static BigDecimal getArithmeticValue(HintContext ctx, TreePath get) { + Number compute = ArithmeticUtilities.compute(ctx.getInfo(), get, true); + if (null != compute) { + return BigDecimal.valueOf(compute.doubleValue()); + } + return null; + } + + private static String getLiteralValue(TreePath get) { + if (get.getLeaf().getKind() == Tree.Kind.STRING_LITERAL) { + return ((LiteralTree) get.getLeaf()).getValue().toString(); + } + return null; + } + + private static boolean isAtLeastJDK5(HintContext ctx) { + return ctx.getInfo().getSourceVersion().compareTo(SourceVersion.RELEASE_5) >= 0; + } + +} --- java.hints/test/unit/src/org/netbeans/modules/java/hints/suggestions/UseBDConstFixTest.java +++ java.hints/test/unit/src/org/netbeans/modules/java/hints/suggestions/UseBDConstFixTest.java @@ -0,0 +1,328 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.modules.java.hints.suggestions; + +import org.junit.Test; +import org.netbeans.modules.java.hints.test.api.HintTest; + +/** + * @author markiewb + */ +public class UseBDConstFixTest { + + @Test + public void testConvertONE_A() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(\"1\");\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:60:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.ONE;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertONE_B() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(\"1.0\");\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:62:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.ONE;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertONE_C() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(1.0);\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:60:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.ONE;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertONE_D() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(1.00d);\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:62:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.ONE;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertTEN_A() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(\"10\");\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:61:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.TEN;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertTEN_B() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(\"10.0\");\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:63:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.TEN;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertTEN_C() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(10.0);\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:61:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.TEN;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertTEN_D() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(10.00d);\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:63:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.TEN;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertZERO_A() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(\"0\");\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:60:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.ZERO;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertZERO_B() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(\"0.0\");\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:62:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.ZERO;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertZERO_C() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(0.0);\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:60:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.ZERO;\n" + + " }\n" + + "}\n"); + + } + + @Test + public void testConvertZERO_D() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=new java.math.BigDecimal(0.00d);\n" + + " }\n" + + "}\n") + .run(UseBDConstFix.class) + .findWarning("3:31-3:62:hint:" + Bundle.DN_UseBigDecimalConstants()) + .applyFix() + .assertCompilable() + .assertOutput("package test;\n" + + "import java.math.BigDecimal;\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " java.math.BigDecimal a=BigDecimal.ZERO;\n" + + " }\n" + + "}\n"); + + } + +}