SuspiciousTernaryOperatorInVarargsCallInspection created: IDEA-244144

GitOrigin-RevId: cc56e98bf46b87d1b685177a72bccfd4fc80a596
This commit is contained in:
Andrey.Cherkasov
2020-09-18 23:04:15 +00:00
committed by intellij-monorepo-bot
parent 11c6134b4a
commit eb5e81dcb4
9 changed files with 205 additions and 0 deletions
@@ -1376,6 +1376,12 @@
bundle="messages.JavaBundle"
key="inspection.redundant.explicit.close"
implementationClass="com.intellij.codeInspection.RedundantExplicitCloseInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="SuspiciousTernaryOperatorInVarargsCall"
groupBundle="messages.InspectionsBundle"
groupKey="group.names.probable.bugs" enabledByDefault="true" level="WARNING"
bundle="messages.JavaBundle"
key="inspection.suspicious.ternary.in.varargs.display.name"
implementationClass="com.intellij.codeInspection.SuspiciousTernaryOperatorInVarargsCallInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="RedundantFileCreation"
groupBundle="messages.InspectionsBundle"
groupKey="group.names.verbose.or.redundant.code.constructs" enabledByDefault="true" level="WARNING"
@@ -0,0 +1,89 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection;
import com.intellij.java.JavaBundle;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.util.ObjectUtils;
import com.siyeh.ig.psiutils.CommentTracker;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class SuspiciousTernaryOperatorInVarargsCallInspection extends AbstractBaseJavaLocalInspectionTool {
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
final PsiMethod method = expression.resolveMethod();
if (method == null || !method.isVarArgs()) return;
final PsiExpression[] args = expression.getArgumentList().getExpressions();
final PsiParameter[] params = method.getParameterList().getParameters();
if (args.length != params.length) return;
int varargsPosition = args.length - 1;
PsiExpression varargsExpression = args[varargsPosition];
final PsiConditionalExpression conditional = ObjectUtils.tryCast(varargsExpression, PsiConditionalExpression.class);
if (conditional == null) return;
final PsiExpression thenExpression = conditional.getThenExpression();
final PsiExpression elseExpression = conditional.getElseExpression();
if (thenExpression == null || elseExpression == null) return;
final PsiType thenType = thenExpression.getType();
final PsiType elseType = elseExpression.getType();
boolean isThenArray = thenType instanceof PsiArrayType;
if (isThenArray == elseType instanceof PsiArrayType) return;
final PsiExpression nonArray = isThenArray ? elseExpression : thenExpression;
PsiType varargsType = varargsExpression.getType();
if (varargsType == null) return;
final String replacementText = String.format("new %s[]{%s}", ((PsiClassReferenceType)varargsType).getName(), nonArray.getText());
holder.registerProblem(nonArray,
JavaBundle.message("inspection.suspicious.ternary.in.varargs.description"),
ProblemHighlightType.WARNING,
new WrapInArrayInitializerFix(replacementText));
}
};
}
private static class WrapInArrayInitializerFix implements LocalQuickFix {
private final String myReplacementText;
WrapInArrayInitializerFix(String replacementText) {
myReplacementText = replacementText;
}
@Nls
@NotNull
@Override
public String getName() {
return CommonQuickFixBundle.message("fix.replace.with.x", myReplacementText);
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return JavaBundle.message("inspection.suspicious.ternary.in.varargs.quickfix");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (element == null || !element.isValid()) return;
CommentTracker commentTracker = new CommentTracker();
commentTracker.replaceAndRestoreComments(element, myReplacementText);
}
}
}
@@ -0,0 +1,17 @@
<html>
<body>
Reports vararg method calls that use a ternary operator with mixed array and non-array branches.<br><br>
When compiled, both branches are wrapped in arrays. As a result, the array branch is turned into
a two-dimensional array, which may indicate a problem.<br><br>
The quick-fix wraps the non-array branch in an array to prevent the compiler from doing the conversion.<br><br>
Example:<br><br>
<code><pre>
// reported call
method(condition ? new String[] {"arg1"} : "arg2");
// after the quick-fix
method(condition ? new String[] {"arg1"} : new String[] {"arg2"});
</pre></code>
<!-- tooltip end -->
<p><small>New in 2020.3</small></p>
</body>
</html>
@@ -0,0 +1,16 @@
// "Replace with 'new Object[]{b}'" "true"
class Test {
public static void main(String[] args) {
Object[] a = {1, 2};
Object b = "hello";
foo(0, a);
foo(0, b);
for (boolean flag : new boolean[]{true, false}) {
foo(0, flag ? a : new Object[]{b});
foo(0, 1, flag ? a : b);
}
}
static void foo(int x, Object... xs) {
}
}
@@ -0,0 +1,18 @@
// "Replace with 'new Serializable[]{b}'" "true"
import java.io.Serializable;
class Test {
public static void main(String[] args) {
Serializable[] a = {1, 2};
Serializable b = "hello";
foo(0, a);
foo(0, b);
for (boolean flag : new boolean[]{true, false}) {
foo(0, flag ? a : new Serializable[]{b});
foo(0, 1, flag ? a : b);
}
}
static void foo(int x, Serializable... xs) {
}
}
@@ -0,0 +1,16 @@
// "Replace with 'new Object[]{b}'" "true"
class Test {
public static void main(String[] args) {
Object[] a = {1, 2};
Object b = "hello";
foo(0, a);
foo(0, b);
for (boolean flag : new boolean[]{true, false}) {
foo(0, flag ? a : b<caret>);
foo(0, 1, flag ? a : b);
}
}
static void foo(int x, Object... xs) {
}
}
@@ -0,0 +1,18 @@
// "Replace with 'new Serializable[]{b}'" "true"
import java.io.Serializable;
class Test {
public static void main(String[] args) {
Serializable[] a = {1, 2};
Serializable b = "hello";
foo(0, a);
foo(0, b);
for (boolean flag : new boolean[]{true, false}) {
foo(0, flag ? a : b<caret>);
foo(0, 1, flag ? a : b);
}
}
static void foo(int x, Serializable... xs) {
}
}
@@ -0,0 +1,22 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.codeInsight.daemon.quickFix;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.SuspiciousTernaryOperatorInVarargsCallInspection;
import org.jetbrains.annotations.NotNull;
public class SuspiciousTernaryOperatorInVarargsCallInspectionTest extends LightQuickFixParameterizedTestCase {
@Override
protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() {
return new LocalInspectionTool[]{
new SuspiciousTernaryOperatorInVarargsCallInspection()
};
}
@Override
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/suspiciousTernaryOperatorInVarargsCall";
}
}
@@ -466,6 +466,9 @@ inspection.handle.signature.use.method.fix.family.name=Use one of method overloa
inspection.handle.signature.use.method.fix.name=Use method ''{0}''
inspection.idempotent.loop.body=Idempotent loop body
inspection.illegal.character=Illegal character
inspection.suspicious.ternary.in.varargs.display.name=Suspicious ternary operator in varargs method call
inspection.suspicious.ternary.in.varargs.description=Ternary operator in varargs call contains array and non-array branches
inspection.suspicious.ternary.in.varargs.quickfix=Wrap in array initializer
inspection.insert.literal.underscores.display.name=Unreadable numeric literal
inspection.insert.literal.underscores.family.name=Insert underscores into numeric literal
inspection.javadoc.dialog.title=Edit Additional Javadoc Tags