From ed9a6cbccebb3654d9308555d8ef9d3f44de23c3 Mon Sep 17 00:00:00 2001 From: "Roman.Ivanov" Date: Fri, 28 Dec 2018 15:56:26 +0700 Subject: [PATCH] WrapperTypeMayBePrimitive: fix visitor not calling parent, add special handling of xValue of boxes --- .../WrapperTypeMayBePrimitiveInspection.java | 58 +++++++++++++++++-- .../afterDoubleIntValue.java | 16 +++++ .../afterFloatIsNan.java | 10 ++++ .../beforeDoubleIntValue.java | 16 +++++ .../beforeFloatIsNan.java | 10 ++++ 5 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/afterDoubleIntValue.java create mode 100644 java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/afterFloatIsNan.java create mode 100644 java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/beforeDoubleIntValue.java create mode 100644 java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/beforeFloatIsNan.java diff --git a/java/java-impl/src/com/intellij/codeInspection/WrapperTypeMayBePrimitiveInspection.java b/java/java-impl/src/com/intellij/codeInspection/WrapperTypeMayBePrimitiveInspection.java index df9ec5b736de..09ab1e3470da 100644 --- a/java/java-impl/src/com/intellij/codeInspection/WrapperTypeMayBePrimitiveInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/WrapperTypeMayBePrimitiveInspection.java @@ -3,6 +3,7 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.Nullability; import com.intellij.codeInspection.dataFlow.NullabilityUtil; +import com.intellij.lang.jvm.JvmModifier; import com.intellij.lang.jvm.types.JvmPrimitiveTypeKind; import com.intellij.openapi.project.Project; import com.intellij.psi.*; @@ -29,6 +30,8 @@ public class WrapperTypeMayBePrimitiveInspection extends AbstractBaseJavaLocalIn private static final Map ourReplacementMap = new HashMap<>(); + private static final Set ourAllowedInstanceCalls = new HashSet<>(); + static { ourReplacementMap.put(CommonClassNames.JAVA_LANG_INTEGER, "parseInt"); ourReplacementMap.put(CommonClassNames.JAVA_LANG_LONG, "parseLong"); @@ -37,6 +40,15 @@ public class WrapperTypeMayBePrimitiveInspection extends AbstractBaseJavaLocalIn ourReplacementMap.put(CommonClassNames.JAVA_LANG_DOUBLE, "parseDouble"); ourReplacementMap.put(CommonClassNames.JAVA_LANG_SHORT, "parseShort"); ourReplacementMap.put(CommonClassNames.JAVA_LANG_BYTE, "parseByte"); + + ourAllowedInstanceCalls.add("isInfinite"); + ourAllowedInstanceCalls.add("isNaN"); + ourAllowedInstanceCalls.add("byteValue"); + ourAllowedInstanceCalls.add("shortValue"); + ourAllowedInstanceCalls.add("intValue"); + ourAllowedInstanceCalls.add("longValue"); + ourAllowedInstanceCalls.add("floatValue"); + ourAllowedInstanceCalls.add("doubleValue"); } private static CallMatcher getValueOfMatcher() { @@ -111,6 +123,7 @@ public class WrapperTypeMayBePrimitiveInspection extends AbstractBaseJavaLocalIn @Override public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); if (!TypeConversionUtil.isPrimitiveWrapper(variable.getType())) return; PsiExpression initializer = variable.getInitializer(); BoxingInfo boxingInfo = new BoxingInfo(variable); @@ -156,12 +169,19 @@ public class WrapperTypeMayBePrimitiveInspection extends AbstractBaseJavaLocalIn return variables; } + private static boolean isAllowedInstanceCall(@NotNull PsiMethodCallExpression call) { + PsiMethod method = call.resolveMethod(); + if (method == null) return false; + if (method.hasModifier(JvmModifier.STATIC)) return false; + return ourAllowedInstanceCalls.contains(call.getMethodExpression().getReferenceName()); + } + private static boolean referenceUseAllowUnboxing(@NotNull PsiReferenceExpression expression, @NotNull BoxingInfo boxingInfo) { PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression).getParent(); PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier(expression); if (call != null) { - return TO_STRING.test(call) || HASH_CODE.test(call); + return TO_STRING.test(call) || HASH_CODE.test(call) || isAllowedInstanceCall(call); } if (parent instanceof PsiExpressionList) { PsiElement grandParent = parent.getParent(); @@ -336,18 +356,46 @@ public class WrapperTypeMayBePrimitiveInspection extends AbstractBaseJavaLocalIn String qualifierTypeText = qualifierType.getCanonicalText(); CommentTracker tracker = new CommentTracker(); String qualifierText = tracker.text(qualifier); + String replacement = findStaticReplacement(call, qualifierText, qualifierTypeText); + if (replacement == null) return; + tracker.replaceAndRestoreComments(call, replacement); + } + + private static String findStaticReplacement(PsiMethodCallExpression call, String qualifierText, String qualifierTypeText) { String methodNameText; + String callName = call.getMethodExpression().getReferenceName(); if (HASH_CODE.test(call)) { methodNameText = "hashCode"; } else if (TO_STRING.test(call)) { methodNameText = "toString"; } - else { - return; + else if ("isInfinite".equals(callName)) { + methodNameText = "isInfinite"; } - String callReplacementText = qualifierTypeText + "." + methodNameText + "(" + qualifierText + ")"; - tracker.replaceAndRestoreComments(call, callReplacementText); + else if ("isNaN".equals(callName)) { + methodNameText = "isNaN"; + } else { + methodNameText = null; + } + if (methodNameText != null) { + return qualifierTypeText + "." + methodNameText + "(" + qualifierText + ")"; + } + String type; + if ("intValue".equals(callName)) { + type = "int"; + } else if ("byteValue".equals(callName)) { + type = "byte"; + } else if ("floatValue".equals(callName)) { + type = "float"; + } else if ("doubleValue".equals(callName)) { + type = "double"; + } else if ("shortValue".equals(callName)) { + type = "short"; + } else { + return null; + } + return "(" + type + ")" + qualifierText; } } } diff --git a/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/afterDoubleIntValue.java b/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/afterDoubleIntValue.java new file mode 100644 index 000000000000..94acef8e827a --- /dev/null +++ b/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/afterDoubleIntValue.java @@ -0,0 +1,16 @@ +// "Convert wrapper type to primitive" "true" +import java.util.*; + +class TypeMayBePrimitive { + private static void test(String s) { + double d = 0d; + if (s != null) { + try { + d = Double.parseDouble(s); + } + catch (NumberFormatException ignore) { } + } + + final int intRating = (int) d; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/afterFloatIsNan.java b/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/afterFloatIsNan.java new file mode 100644 index 000000000000..e1ab4983ae0f --- /dev/null +++ b/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/afterFloatIsNan.java @@ -0,0 +1,10 @@ +// "Convert wrapper type to primitive" "true" +import java.util.*; + +class TypeMayBePrimitive { + private static void test(String s) { + float f = 0.0f; + boolean inf = Float.isInfinite(f); + boolean nan = Float.isNaN(f); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/beforeDoubleIntValue.java b/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/beforeDoubleIntValue.java new file mode 100644 index 000000000000..118faf21e366 --- /dev/null +++ b/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/beforeDoubleIntValue.java @@ -0,0 +1,16 @@ +// "Convert wrapper type to primitive" "true" +import java.util.*; + +class TypeMayBePrimitive { + private static void test(String s) { + Double d = 0d; + if (s != null) { + try { + d = Double.valueOf(s); + } + catch (NumberFormatException ignore) { } + } + + final int intRating = d.intValue(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/beforeFloatIsNan.java b/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/beforeFloatIsNan.java new file mode 100644 index 000000000000..6d2ef036cb2f --- /dev/null +++ b/java/java-tests/testData/inspection/wrapperTypeMayBePrimitive/beforeFloatIsNan.java @@ -0,0 +1,10 @@ +// "Convert wrapper type to primitive" "true" +import java.util.*; + +class TypeMayBePrimitive { + private static void test(String s) { + Float f = 0.0f; + boolean inf = f.isInfinite(); + boolean nan = f.isNaN(); + } +} \ No newline at end of file