IDEA-259356 inspection 'same parameter value': add option to ignore cases without quick-fix

GitOrigin-RevId: b9f41d65fd21be0052fdae3b2b01027043778ba9
This commit is contained in:
Alexandr Suhinin
2021-07-19 08:50:34 +00:00
committed by intellij-monorepo-bot
parent e6472aeb09
commit 5f70aac2f8
11 changed files with 115 additions and 11 deletions
@@ -31,6 +31,7 @@ import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.InlineUtil;
import com.intellij.uast.UastHintedVisitorAdapter;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.fields.IntegerField;
import com.intellij.ui.components.fields.valueEditors.ValueEditor;
import com.intellij.util.IncorrectOperationException;
@@ -57,11 +58,17 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool
@PsiModifier.ModifierConstant
public String highestModifier = DEFAULT_HIGHEST_MODIFIER;
public int minimalUsageCount = 1;
public boolean ignoreWhenRefactoringIsComplicated = true;
@Nullable
@Override
public JComponent createOptionsPanel() {
JPanel panel = new InspectionOptionsPanel();
final JBCheckBox checkBox = new JBCheckBox(JavaBundle.message("label.ignore.complicated.fix"), ignoreWhenRefactoringIsComplicated);
checkBox.addChangeListener((e) -> ignoreWhenRefactoringIsComplicated = checkBox.isSelected());
panel.add(checkBox);
LabeledComponent<VisibilityModifierChooser> component = LabeledComponent.create(new VisibilityModifierChooser(() -> true,
highestModifier,
(newModifier) -> highestModifier = newModifier),
@@ -111,7 +118,9 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool
if (problems == null) problems = new ArrayList<>(1);
UParameter parameter = refParameter.getUastElement();
if (parameter == null) continue;
problems.add(registerProblem(manager, parameter, value, refParameter.isUsedForWriting()));
Boolean isFixAvailable = isFixAvailable(parameter, value, refParameter.isUsedForWriting());
if (Boolean.FALSE.equals(isFixAvailable) && ignoreWhenRefactoringIsComplicated) return null;
problems.add(registerProblem(manager, parameter, value, Boolean.TRUE.equals(isFixAvailable)));
}
}
}
@@ -181,20 +190,17 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool
private ProblemDescriptor registerProblem(@NotNull InspectionManager manager,
UParameter parameter,
Object value,
boolean usedForWriting) {
boolean suggestFix) {
final String name = parameter.getName();
String shortName;
String stringPresentation;
boolean accessible = true;
PsiParameter javaParameter = ObjectUtils.tryCast(parameter.getSourcePsi(), PsiParameter.class);
if (value instanceof PsiType) {
stringPresentation = ((PsiType)value).getCanonicalText() + ".class";
shortName = ((PsiType)value).getPresentableText() + ".class";
}
else {
if (value instanceof PsiField) {
accessible = javaParameter != null && PsiUtil.isMemberAccessibleAt((PsiMember)value, javaParameter);
stringPresentation = PsiFormatUtil.formatVariable((PsiVariable)value,
PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_FQ_NAME,
PsiSubstitutor.EMPTY);
@@ -209,10 +215,6 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool
stringPresentation = shortName = String.valueOf(value);
}
}
boolean suggestFix = false;
if (javaParameter != null) {
suggestFix = !javaParameter.isVarArgs() && !usedForWriting && accessible ;
}
return manager.createProblemDescriptor(ObjectUtils.notNull(UDeclarationKt.getAnchorPsi(parameter), parameter),
JavaBundle.message("inspection.same.parameter.problem.descriptor",
name,
@@ -221,6 +223,17 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false);
}
protected static @Nullable Boolean isFixAvailable(UParameter parameter, Object value, boolean usedForWriting) {
if (usedForWriting) return false;
PsiParameter javaParameter = ObjectUtils.tryCast(parameter.getSourcePsi(), PsiParameter.class);
if (javaParameter == null) return null;
if (javaParameter.isVarArgs()) return false;
if (value instanceof PsiField && !PsiUtil.isMemberAccessibleAt((PsiMember)value, javaParameter)) {
return false;
}
return true;
}
public static final class InlineParameterValueFix implements LocalQuickFix {
private final String myValue;
private final String myParameterName;
@@ -456,7 +469,10 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool
for (int i = 0, length = paramValues.length; i < length; i++) {
Object value = paramValues[i];
if (value != VALUE_UNDEFINED && value != VALUE_IS_NOT_CONST) {
holder.registerProblem(registerProblem(holder.getManager(), parameters.get(i), value, false));
final UParameter parameter = parameters.get(i);
Boolean isFixAvailable = isFixAvailable(parameter, value, false);
if (Boolean.FALSE.equals(isFixAvailable) && ignoreWhenRefactoringIsComplicated) return true;
holder.registerProblem(registerProblem(holder.getManager(), parameter, value, Boolean.TRUE.equals(isFixAvailable)));
}
}
}
@@ -15,5 +15,10 @@ public static void main(String[] args) {
</code>
</pre>
<p>The quick-fix inlines the constant value. This may simplify the method implementation.</p>
<!-- tooltip end -->
<p>
Use the checkbox below to ignore cases when complicated refactoring may be required.
For example, when the reported parameter is modified inside the method or when the passed parameter value is a reference to inaccessible field.
</p>
</body>
</html>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Test.java</file>
<line>10</line>
<description>Actual value of parameter 'obj' is always 'A.OBJ'</description>
</problem>
</problems>
@@ -0,0 +1,13 @@
class A {
public static final Object OBJ = new Object();
void test() {
B.use(OBJ);
}
}
class B {
static void use(Object obj) {
System.out.println(obj);
}
}
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems/>
@@ -0,0 +1,13 @@
class A {
private static final Object OBJ = new Object();
void test() {
B.use(OBJ);
}
}
class B {
static void use(Object obj) {
System.out.println(obj);
}
}
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Test.java</file>
<line>10</line>
<description>Actual value of parameter 'obj' is always 'A.OBJ'</description>
</problem>
</problems>
@@ -0,0 +1,13 @@
class A {
private static final Object OBJ = new Object();
void test() {
B.use(OBJ);
}
}
class B {
static void use(Object obj) {
System.out.println(obj);
}
}
@@ -80,6 +80,20 @@ public class SameParameterValueLocalTest extends JavaInspectionTestCase {
doTest(getGlobalTestDir(), myTool);
}
public void testFixAvailable() { doTest(getGlobalTestDir(), myTool); }
public void testFixNotAvailable() { doTest(getGlobalTestDir(), myTool); }
public void testFixNotAvailableIsShown() {
boolean previous = myGlobalTool.ignoreWhenRefactoringIsComplicated;
try {
myGlobalTool.ignoreWhenRefactoringIsComplicated = false;
doTest(getGlobalTestDir(), myTool);
} finally {
myGlobalTool.ignoreWhenRefactoringIsComplicated = previous;
}
}
public void testUsageCount() {
int previous = myGlobalTool.minimalUsageCount;
try {
@@ -62,7 +62,13 @@ public class SameParameterValueTest extends JavaInspectionTestCase {
}
public void testSimpleVararg() {
doTest(getTestDir(), myTool, false, true);
boolean previous = myTool.ignoreWhenRefactoringIsComplicated;
try {
myTool.ignoreWhenRefactoringIsComplicated = false;
doTest(getTestDir(), myTool, false, true);
} finally {
myTool.ignoreWhenRefactoringIsComplicated = previous;
}
}
public void testMethodWithSuper() {
@@ -959,6 +959,7 @@ label.implements.method.of_class_or_interface.name=implements method of {0, choi
label.implements.method.of_interfaces=implements methods of the following classes/interfaces:
label.maximal.reported.method.visibility=Maximal reported method visibility:
label.method=Method ''{0}''
label.ignore.complicated.fix=Ignore when complicated refactoring may be required
label.minimal.reported.method.usage.count=Minimal reported method usage count:
label.minimal.reported.method.visibility=Minimal reported method visibility:
label.mutates=Mutates: