From 20dbc2b67ce0df2e2c87d5dd441c9a3194462da6 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 5 Aug 2013 17:22:51 +0200 Subject: [PATCH] IDEA-111571 (boxing and unboxing with a cast not reported by inspections) --- .../siyeh/ig/jdk/AutoBoxingInspection.java | 12 +++-- .../siyeh/ig/jdk/AutoUnboxingInspection.java | 53 +++++++++++++------ .../siyeh/ig/psiutils/ExpectedTypeUtils.java | 17 +++++- .../igtest/jdk/auto_boxing/AutoBoxing.java | 5 ++ .../siyeh/igtest/jdk/auto_boxing/expected.xml | 14 +++++ .../jdk/auto_unboxing/AutoUnboxing.java | 5 ++ .../igtest/jdk/auto_unboxing/expected.xml | 13 +++++ 7 files changed, 98 insertions(+), 21 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AutoBoxingInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AutoBoxingInspection.java index 270192124467..798d53e84020 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AutoBoxingInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AutoBoxingInspection.java @@ -111,7 +111,7 @@ public class AutoBoxingInspection extends BaseInspection { @Override public void doFix(Project project, ProblemDescriptor descriptor) { final PsiExpression expression = (PsiExpression)descriptor.getPsiElement(); - final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false); + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false, true); if (expectedType == null) { return; } @@ -146,7 +146,13 @@ public class AutoBoxingInspection extends BaseInspection { else { newExpression = classToConstruct + ".valueOf(" + expressionText + ')'; } - replaceExpression(expression, newExpression); + final PsiElement parent = expression.getParent(); + if (parent instanceof PsiTypeCastExpression) { + final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)parent; + replaceExpression(typeCastExpression, newExpression); + } else { + replaceExpression(expression, newExpression); + } } private static boolean shortcutReplace(PsiExpression expression, String classToConstruct) { @@ -303,7 +309,7 @@ public class AutoBoxingInspection extends BaseInspection { if (boxedType == null) { return; } - final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false); + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false, true); if (expectedType == null || ClassUtils.isPrimitive(expectedType)) { return; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AutoUnboxingInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AutoUnboxingInspection.java index bea3864a7646..5d6f7139b2f2 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AutoUnboxingInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AutoUnboxingInspection.java @@ -37,9 +37,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class AutoUnboxingInspection extends BaseInspection { @@ -59,6 +57,19 @@ public class AutoUnboxingInspection extends BaseInspection { s_unboxingMethods.put("char", "charValue"); } + @NonNls static final Set unboxableTypes = new HashSet(9); + static { + unboxableTypes.add(CommonClassNames.JAVA_LANG_BYTE); + unboxableTypes.add(CommonClassNames.JAVA_LANG_SHORT); + unboxableTypes.add(CommonClassNames.JAVA_LANG_INTEGER); + unboxableTypes.add(CommonClassNames.JAVA_LANG_LONG); + unboxableTypes.add(CommonClassNames.JAVA_LANG_FLOAT); + unboxableTypes.add(CommonClassNames.JAVA_LANG_DOUBLE); + unboxableTypes.add(CommonClassNames.JAVA_LANG_BOOLEAN); + unboxableTypes.add(CommonClassNames.JAVA_LANG_CHARACTER); + unboxableTypes.add(CommonClassNames.JAVA_LANG_OBJECT); + } + @Override @NotNull public String getDisplayName() { @@ -131,7 +142,7 @@ public class AutoUnboxingInspection extends BaseInspection { if (type == null) { return; } - final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type); + final PsiPrimitiveType unboxedType = (PsiPrimitiveType)ExpectedTypeUtils.findExpectedType(expression, false, true); if (unboxedType == null) { return; } @@ -140,7 +151,11 @@ public class AutoUnboxingInspection extends BaseInspection { final PsiElementFactory factory = psiFacade.getElementFactory(); final PsiElement parent = expression.getParent(); final String expressionText = expression.getText(); - if (parent instanceof PsiPrefixExpression && !unboxedType.equalsToText("boolean")) { + if (parent instanceof PsiTypeCastExpression) { + final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)parent; + replaceExpression(typeCastExpression, newExpressionText); + } + else if (parent instanceof PsiPrefixExpression && !unboxedType.equalsToText("boolean")) { final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)parent; final IElementType tokenType = prefixExpression.getOperationTokenType(); if (JavaTokenType.PLUSPLUS.equals(tokenType)) { @@ -205,7 +220,7 @@ public class AutoUnboxingInspection extends BaseInspection { } } - private static String buildNewExpressionText(PsiExpression expression, PsiType unboxedType) { + private static String buildNewExpressionText(PsiExpression expression, PsiPrimitiveType unboxedType) { final String unboxedTypeText = unboxedType.getCanonicalText(); final String expressionText = expression.getText(); final String boxMethodName = s_unboxingMethods.get(unboxedTypeText); @@ -225,6 +240,10 @@ public class AutoUnboxingInspection extends BaseInspection { return argument.getText(); } } + final PsiType type = expression.getType(); + if (type != null && type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { + return "((" + unboxedType.getBoxedTypeName() + ')' + expressionText + ")." + boxMethodName + "()"; + } return expressionText + '.' + boxMethodName + "()"; } @@ -365,21 +384,23 @@ public class AutoUnboxingInspection extends BaseInspection { if (TypeConversionUtil.isPrimitiveAndNotNull(expressionType)) { return; } - final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(expressionType); - if (unboxedType == null) { + if (!isUnboxable(expressionType)) { return; } - final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false); - if (expectedType == null) { - return; - } - if (!TypeConversionUtil.isPrimitiveAndNotNull(expectedType)) { - return; - } - if (!expectedType.isAssignableFrom(unboxedType)) { + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false, true); + if (expectedType == null || !TypeConversionUtil.isPrimitiveAndNotNull(expectedType)) { return; } registerError(expression, expression); } + + private static boolean isUnboxable(PsiType type) { + if (!(type instanceof PsiClassType)) { + return false; + } + final PsiClassType classType = (PsiClassType)type; + final PsiClass aClass = classType.resolve(); + return aClass != null && unboxableTypes.contains(aClass.getQualifiedName()); + } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java index 87ec266694b2..c14da9f55373 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java @@ -33,6 +33,10 @@ public class ExpectedTypeUtils { @Nullable public static PsiType findExpectedType(@NotNull PsiExpression expression, boolean calculateTypeForComplexReferences) { + return findExpectedType(expression, calculateTypeForComplexReferences, false); + } + + public static PsiType findExpectedType(PsiExpression expression, boolean calculateTypeForComplexReferences, boolean reportCasts) { PsiElement context = expression.getParent(); PsiExpression wrappedExpression = expression; while (context instanceof PsiParenthesizedExpression) { @@ -42,7 +46,7 @@ public class ExpectedTypeUtils { if (context == null) { return null; } - final ExpectedTypeVisitor visitor = new ExpectedTypeVisitor(wrappedExpression, calculateTypeForComplexReferences); + final ExpectedTypeVisitor visitor = new ExpectedTypeVisitor(wrappedExpression, calculateTypeForComplexReferences, reportCasts); context.accept(visitor); return visitor.getExpectedType(); } @@ -92,11 +96,13 @@ public class ExpectedTypeUtils { @NotNull private final PsiExpression wrappedExpression; private final boolean calculateTypeForComplexReferences; + private final boolean reportCasts; private PsiType expectedType = null; - ExpectedTypeVisitor(@NotNull PsiExpression wrappedExpression, boolean calculateTypeForComplexReferences) { + ExpectedTypeVisitor(@NotNull PsiExpression wrappedExpression, boolean calculateTypeForComplexReferences, boolean reportCasts) { this.wrappedExpression = wrappedExpression; this.calculateTypeForComplexReferences = calculateTypeForComplexReferences; + this.reportCasts = reportCasts; } public PsiType getExpectedType() { @@ -295,6 +301,13 @@ public class ExpectedTypeUtils { } } + @Override + public void visitTypeCastExpression(PsiTypeCastExpression expression) { + if (reportCasts) { + expectedType = expression.getType(); + } + } + @Override public void visitWhileStatement(@NotNull PsiWhileStatement whileStatement) { expectedType = PsiType.BOOLEAN; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_boxing/AutoBoxing.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_boxing/AutoBoxing.java index 883b3e2e5a46..2cec0b8b7eb9 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_boxing/AutoBoxing.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_boxing/AutoBoxing.java @@ -53,4 +53,9 @@ public class AutoBoxing { void doInstanceof(Object o) { Boolean b = o instanceof String; } + + void m(boolean b) { + System.out.println((Boolean)b); + final Object o1 = (Object) b; + } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_boxing/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_boxing/expected.xml index c5867eeadea1..614cad761ab3 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_boxing/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_boxing/expected.xml @@ -93,4 +93,18 @@ Auto-boxing <code>o instanceof String</code> #loc + + AutoBoxing.java + 58 + Auto-boxing + Auto-boxing <code>b</code> #loc + + + + AutoBoxing.java + 59 + Auto-boxing + Auto-boxing <code>b</code> #loc + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java index 457f01e7d329..cc872129b63e 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java @@ -53,4 +53,9 @@ public class AutoUnboxing { default: } } + + void m(Object o, Boolean b) { + if ((boolean) o) {} + if ((boolean) b) {} + } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml index 6723165f616c..b42d1de62abf 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml @@ -85,4 +85,17 @@ Auto-unboxing <code>i</code> #loc + + AutoUnboxing.java + 58 + Auto-unboxing + Auto-unboxing <code>o</code> #loc + + + + AutoUnboxing.java + 59 + Auto-unboxing + Auto-unboxing <code>b</code> #loc + \ No newline at end of file