[java-inspections] PatternVariableCanBeUsed: false positives

IDEA-301287

GitOrigin-RevId: 84f0eaf8d62b5ab76be7f25c078bfb5fc24bb889
This commit is contained in:
Andrey.Cherkasov
2022-09-15 19:40:45 +00:00
committed by intellij-monorepo-bot
parent c94c20ff53
commit 39e0598cb7
5 changed files with 55 additions and 9 deletions
@@ -36,10 +36,13 @@ public class PatternVariableCanBeUsedInspection extends AbstractBaseJavaLocalIns
if (qualifier == null) return;
if (qualifier.resolve() instanceof PsiPatternVariable variable &&
variable.getPattern() instanceof PsiDeconstructionPattern deconstruction) {
if (!isFinalOrEffectivelyFinal(variable)) return;
PsiPatternVariable existingPatternVariable = findExistingPatternVariable(qualifier, deconstruction, call);
if (existingPatternVariable == null) return;
if (!isFinalOrEffectivelyFinal(existingPatternVariable)) return;
String patternName = existingPatternVariable.getName();
if (PsiUtil.skipParenthesizedExprUp(call.getParent()) instanceof PsiLocalVariable localVariable) {
if (PsiUtil.skipParenthesizedExprUp(call.getParent()) instanceof PsiLocalVariable localVariable &&
canReplaceLocalVariableWithPatternVariable(localVariable, existingPatternVariable)) {
String name = localVariable.getName();
LocalQuickFix fix = new ExistingPatternVariableCanBeUsedFix(name, existingPatternVariable);
holder.registerProblem(call, InspectionGadgetsBundle.message("inspection.pattern.variable.can.be.used.existing.message",
@@ -54,6 +57,20 @@ public class PatternVariableCanBeUsedInspection extends AbstractBaseJavaLocalIns
}
}
private static boolean isFinalOrEffectivelyFinal(@NotNull PsiPatternVariable variable) {
return (!(variable.getPattern() instanceof PsiDeconstructionPattern) && variable.hasModifierProperty(PsiModifier.FINAL)) ||
!VariableAccessUtils.variableIsAssigned(variable, variable.getDeclarationScope());
}
private static boolean canReplaceLocalVariableWithPatternVariable(@NotNull PsiLocalVariable localVariable,
@NotNull PsiPatternVariable patternVariable) {
PsiElement scope = PsiUtil.getVariableCodeBlock(localVariable, null);
if (scope == null) return false;
return localVariable.hasModifierProperty(PsiModifier.FINAL) ||
!patternVariable.hasModifierProperty(PsiModifier.FINAL) ||
HighlightControlFlowUtil.isEffectivelyFinal(localVariable, scope, null);
}
@Nullable
private static PsiReferenceExpression getQualifierReferenceExpression(@NotNull PsiMethodCallExpression call) {
while (true) {
@@ -110,17 +127,18 @@ public class PatternVariableCanBeUsedInspection extends AbstractBaseJavaLocalIns
if (scope == null) return;
PsiDeclarationStatement declaration = ObjectUtils.tryCast(variable.getParent(), PsiDeclarationStatement.class);
if (declaration == null) return;
if (!PsiUtil.isLanguageLevel16OrHigher(holder.getFile()) &&
!variable.hasModifierProperty(PsiModifier.FINAL) &&
!HighlightControlFlowUtil.isEffectivelyFinal(variable, scope, null)) return;
PsiInstanceOfExpression instanceOf = InstanceOfUtils.findPatternCandidate(cast);
if (instanceOf != null) {
PsiPattern pattern = instanceOf.getPattern();
PsiPatternVariable existingPatternVariable = JavaPsiPatternUtil.getPatternVariable(pattern);
String name = identifier.getText();
if (existingPatternVariable != null) {
if (!canReplaceLocalVariableWithPatternVariable(variable, existingPatternVariable) ||
!isFinalOrEffectivelyFinal(existingPatternVariable)) {
return;
}
holder.registerProblem(identifier,
InspectionGadgetsBundle.message("inspection.pattern.variable.can.be.used.existing.message",
InspectionGadgetsBundle.message("inspection.pattern.variable.can.be.used.existing.message",
existingPatternVariable.getName(), name),
new ExistingPatternVariableCanBeUsedFix(name, existingPatternVariable));
} else {
@@ -1,14 +1,19 @@
// "Fix all 'Pattern variable can be used' problems in file" "true"
class Main {
void foo(Object obj) {
if (obj instanceof Rect(Point(double x1, double y1), Point(double x2, double y2)) rect) {
if (obj instanceof Rect(Point(double x1, double y1) point1, Point(final double x2, double y2)) rect) {
System.out.println(x2);
double x = x1;
Point p1 = rect.point2();
System.out.println(rect.point2().z());
System.out.println(rect.point1().y());
System.out.println(rect.point1().z());
y2 = 0.0;
System.out.println(rect.point2().y());
point1 = new Point(100.0, 200.0);
System.out.println(point1.y());
double d = x2;
d = 10.0;
}
}
}
@@ -0,0 +1,9 @@
// "Replace 'integer' with existing pattern variable 'i'" "false"
class X {
void test(Object obj) {
if (obj instanceof Integer i) {
i = 42;
Integer <caret>integer = (Integer)obj;
}
}
}
@@ -0,0 +1,9 @@
// "Replace 'integer' with existing pattern variable 'i'" "false"
class X {
void test(Object obj) {
if (obj instanceof final Integer i) {
Integer <caret>integer = (Integer)obj;
integer = 42;
}
}
}
@@ -1,14 +1,19 @@
// "Fix all 'Pattern variable can be used' problems in file" "true"
class Main {
void foo(Object obj) {
if (obj instanceof Rect(Point(double x1, double y1), Point(double x2, double y2)) rect) {
if (obj instanceof Rect(Point(double x1, double y1) point1, Point(final double x2, double y2)) rect) {
System.out.println(rect.point2().x(<caret>));
double x = x1;
Point p1 = rect.point2();
System.out.println(rect.point2().z());
System.out.println(rect.point1().y());
System.out.println(rect.point1().z());
y2 = 0.0;
System.out.println(rect.point2().y());
point1 = new Point(100.0, 200.0);
System.out.println(point1.y());
double d = rect.point2().x();
d = 10.0;
}
}
}