From 3d6b0b432c662e4a0860c6d5a5f8bfe8cf5929f4 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sat, 12 Apr 2025 16:12:47 +0200 Subject: [PATCH] Java: don't report redundant cast on primitive array argument to vararg method (IDEA-273298) GitOrigin-RevId: 938943d615f628bffe7fe493cfc5f408ff3592d0 --- .../RedundantCastInspection.java | 20 ++++-- ...ArgumentToVariableArgMethodInspection.java | 70 +++++++++---------- ...itiveArrayArgumentToVariableArgMethod.java | 2 + .../inspection/redundantCast/Vararg.java | 10 +++ .../RedundantCastInspectionTest.java | 3 +- 5 files changed, 62 insertions(+), 43 deletions(-) create mode 100644 java/java-tests/testData/inspection/redundantCast/Vararg.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java index a3008ca4f652..918b308e5b16 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInspection.redundantCast; import com.intellij.codeInspection.*; @@ -14,6 +14,7 @@ import com.intellij.psi.util.PsiExpressionTrimRenderer; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.RedundantCastUtil; import com.intellij.util.ObjectUtils; +import com.siyeh.ig.bugs.PrimitiveArrayArgumentToVariableArgMethodInspection; import com.siyeh.ig.callMatcher.CallMatcher; import com.siyeh.ig.format.FormatDecode; import com.siyeh.ig.psiutils.CommentTracker; @@ -89,15 +90,22 @@ public final class RedundantCastInspection extends AbstractBaseJavaLocalInspecti PsiElement parent = PsiUtil.skipParenthesizedExprUp(cast.getParent()); if (parent instanceof PsiExpressionList) { final PsiElement gParent = parent.getParent(); - if (gParent instanceof PsiMethodCallExpression && IGNORE_SUSPICIOUS_METHOD_CALLS) { + if (gParent instanceof PsiMethodCallExpression call && IGNORE_SUSPICIOUS_METHOD_CALLS) { PsiType operandType = operand.getType(); - final String message = SuspiciousMethodCallUtil - .getSuspiciousMethodCallMessage((PsiMethodCallExpression)gParent, operand, operandType, true, new ArrayList<>(), 0); + final String message = + SuspiciousMethodCallUtil.getSuspiciousMethodCallMessage(call, operand, operandType, true, new ArrayList<>(), 0); if (message != null) { return null; } - - if (FormatDecode.isSuspiciousFormatCall((PsiMethodCallExpression)gParent, cast)) { + PsiExpression[] arguments = call.getArgumentList().getExpressions(); + if (arguments.length > 0) { + PsiExpression lastArgument = arguments[arguments.length - 1]; + if (lastArgument == cast + && PrimitiveArrayArgumentToVariableArgMethodInspection.isConfusingArgument(call, operand, arguments)) { + return null; + } + } + if (FormatDecode.isSuspiciousFormatCall(call, cast)) { return null; } diff --git a/java/java-analysis-impl/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java b/java/java-analysis-impl/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java index 6678e78a0aea..81f8a240b590 100644 --- a/java/java-analysis-impl/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java +++ b/java/java-analysis-impl/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2017 Dave Griffith, Bas Leijdekkers + * Copyright 2006-2025 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,16 @@ package com.siyeh.ig.bugs; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.daemon.impl.quickfix.AddTypeCastFix; import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.openapi.project.Project; import com.intellij.pom.java.JavaFeature; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.TypeConversionUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.TypeUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Set; @@ -37,7 +39,7 @@ public final class PrimitiveArrayArgumentToVariableArgMethodInspection extends B } @Override - public @Nullable String getAlternativeID() { + public @NotNull String getAlternativeID() { return "PrimitiveArrayArgumentToVariableArgMethod"; // keep old suppression working } @@ -59,7 +61,8 @@ public final class PrimitiveArrayArgumentToVariableArgMethodInspection extends B @Override protected @NotNull LocalQuickFix buildFix(Object... infos) { final PsiExpression argument = (PsiExpression)infos[0]; - final PsiType type = (PsiType)infos[1]; + Project project = argument.getProject(); + final PsiType type = PsiType.getJavaLangObject(PsiManager.getInstance(project), GlobalSearchScope.allScope(project)); return LocalQuickFix.from(new AddTypeCastFix(type, argument)); } @@ -92,46 +95,41 @@ public final class PrimitiveArrayArgumentToVariableArgMethodInspection extends B return; } final PsiExpression lastArgument = arguments[arguments.length - 1]; - final PsiType argumentType = lastArgument.getType(); - if (!isPrimitiveArrayType(argumentType)) { + if (!isConfusingArgument(call, lastArgument, arguments)) { return; } - final JavaResolveResult result = call.resolveMethodGenerics(); - final PsiMethod method = (PsiMethod)result.getElement(); - if (method == null || AnnotationUtil.isAnnotated(method, CommonClassNames.JAVA_LANG_INVOKE_MH_POLYMORPHIC, 0)) { - return; - } - final PsiParameterList parameterList = method.getParameterList(); - if (parameterList.getParametersCount() != arguments.length) { - return; - } - final PsiParameter[] parameters = parameterList.getParameters(); - final PsiParameter lastParameter = parameters[parameters.length - 1]; - if (!lastParameter.isVarArgs()) { - return; - } - final PsiEllipsisType parameterType = (PsiEllipsisType)lastParameter.getType(); - if (isDeepPrimitiveArrayType(parameterType, result.getSubstitutor())) { - return; - } - registerError(lastArgument, lastArgument, parameterType.getComponentType()); + registerError(lastArgument, lastArgument); } } - static boolean isPrimitiveArrayType(PsiType type) { - if (!(type instanceof PsiArrayType)) { + public static boolean isConfusingArgument(@NotNull PsiCall call, PsiExpression argument, PsiExpression[] arguments) { + if (!isPrimitiveArrayType(argument.getType())) { return false; } - final PsiType componentType = ((PsiArrayType)type).getComponentType(); - return TypeConversionUtil.isPrimitiveAndNotNull(componentType); + final JavaResolveResult result = call.resolveMethodGenerics(); + final PsiMethod method = (PsiMethod)result.getElement(); + if (method == null || !method.isVarArgs() + || AnnotationUtil.isAnnotated(method, CommonClassNames.JAVA_LANG_INVOKE_MH_POLYMORPHIC, 0)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + int count = parameterList.getParametersCount(); + if (count != arguments.length) { + return false; + } + final PsiParameter lastParameter = parameterList.getParameter(count - 1); + if (lastParameter == null || !lastParameter.isVarArgs()) { + return false; + } + final PsiEllipsisType parameterType = (PsiEllipsisType)lastParameter.getType(); + final PsiType componentType = parameterType.getComponentType(); + if (!TypeUtils.isJavaLangObject(result.getSubstitutor().substitute(componentType))) { + return false; + } + return true; } - static boolean isDeepPrimitiveArrayType(PsiType type, PsiSubstitutor substitutor) { - if (!(type instanceof PsiEllipsisType)) { - return false; - } - final PsiType componentType = type.getDeepComponentType(); - final PsiType substitute = substitutor.substitute(componentType); - return TypeConversionUtil.isPrimitiveAndNotNull(substitute.getDeepComponentType()); + private static boolean isPrimitiveArrayType(PsiType type) { + return type instanceof PsiArrayType arrayType && TypeConversionUtil.isPrimitiveAndNotNull(arrayType.getComponentType()); } } \ No newline at end of file diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java b/java/java-tests/testData/ig/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java index 471879f00549..e6fe5db702ee 100644 --- a/java/java-tests/testData/ig/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java +++ b/java/java-tests/testData/ig/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java @@ -30,6 +30,8 @@ public class PrimitiveArrayArgumentToVariableArgMethod void foo(byte[] bs) { final X x = new X(); x.method(bs); + final X y = new X(); + y.method(bs); } void m() { diff --git a/java/java-tests/testData/inspection/redundantCast/Vararg.java b/java/java-tests/testData/inspection/redundantCast/Vararg.java new file mode 100644 index 000000000000..6caf3f1f8002 --- /dev/null +++ b/java/java-tests/testData/inspection/redundantCast/Vararg.java @@ -0,0 +1,10 @@ +public class Vararg { + + public void x() { + int[] ints = new int[]{1, 2, 3}; + doSomething((Object) ints); // inspection shown with and without cast to Object + System.out.printf("%s", (Object) new int[] {1, 2, 3}); + } + + void doSomething(Object... args) {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/RedundantCastInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/RedundantCastInspectionTest.java index 68c7d2f09c67..2a8911799c08 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/RedundantCastInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/RedundantCastInspectionTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.codeInspection; import com.intellij.JavaTestUtil; @@ -71,6 +71,7 @@ public class RedundantCastInspectionTest extends LightJavaCodeInsightFixtureTest public void testInConditionalPreserveResolve() { doTest(); } public void testArrayAccess() { doTest(); } public void testSwitchUnboxing() { doTest(); } + public void testVararg() { doTest(); } public void testPackagePrivate() { myFixture.addClass("package a; public class A {void foo() {}}");