[java-inspection] IDEA-311157 deleting component doesn't check usages

- fix recursive call with unconditional

GitOrigin-RevId: fb08111db21de7acb23ddef7368c1880da361e82
This commit is contained in:
Mikhail Pyltsin
2024-12-02 21:32:33 +01:00
committed by intellij-monorepo-bot
parent beb68b6539
commit bd9dc78aae
3 changed files with 58 additions and 17 deletions

View File

@@ -1387,7 +1387,7 @@ public final class JavaChangeSignatureUsageProcessor implements ChangeSignatureU
public static void checkParametersToDelete(PsiMethod method,
boolean[] toRemove,
MultiMap<PsiElement, @DialogMessage String> conflictDescriptions) {
checkRecordComponents(method, toRemove, conflictDescriptions);
checkRecordComponentsToDelete(method, toRemove, conflictDescriptions);
if (method instanceof SyntheticElement) return;
final PsiParameter[] parameters = method.getParameterList().getParameters();
final PsiCodeBlock body = method.getBody();
@@ -1408,9 +1408,9 @@ public final class JavaChangeSignatureUsageProcessor implements ChangeSignatureU
}
}
private static void checkRecordComponents(@NotNull PsiMethod method,
boolean[] toRemove,
@NotNull MultiMap<PsiElement, @DialogMessage String> conflictDescriptions) {
private static void checkRecordComponentsToDelete(@NotNull PsiMethod method,
boolean[] toRemove,
@NotNull MultiMap<PsiElement, @DialogMessage String> conflictDescriptions) {
PsiClass aClass = method.getContainingClass();
if (aClass == null || !aClass.isRecord()) return;
if (!JavaPsiRecordUtil.isCanonicalConstructor(method)) return;
@@ -1459,34 +1459,43 @@ public final class JavaChangeSignatureUsageProcessor implements ChangeSignatureU
PsiPattern[] deconstructionComponents = deconstructionPattern.getDeconstructionList().getDeconstructionComponents();
PsiPattern deconstructionComponent = deconstructionComponents[i];
PsiRecordComponent recordComponent = components[i];
if (!JavaPsiPatternUtil.isUnconditionalForType(deconstructionComponent, recordComponent.getType(), true)) {
conflictDescriptions.putValue(deconstructionComponent,
JavaRefactoringBundle.message("record.component.used.in.method.body.warning",
recordComponent.getName()));
}
collectDeconstructionRecordUsagesConflict(deconstructionComponent, aClass, conflictDescriptions, recordComponent);
collectDeconstructionRecordToDeleteUsagesConflict(deconstructionComponent, aClass, conflictDescriptions, recordComponent);
}
}
}
}
private static void collectDeconstructionRecordUsagesConflict(@Nullable PsiPattern pattern,
@NotNull PsiClass aClass,
@NotNull MultiMap<PsiElement, String> conflictDescriptions,
@NotNull PsiRecordComponent recordComponent) {
private static void collectDeconstructionRecordToDeleteUsagesConflict(@Nullable PsiPattern pattern,
@NotNull PsiClass context,
@NotNull MultiMap<PsiElement, String> conflictDescriptions,
@NotNull PsiRecordComponent recordComponent) {
if (pattern == null) return;
if (!JavaPsiPatternUtil.isUnconditionalForType(pattern, recordComponent.getType(), true)) {
conflictDescriptions.putValue(pattern, JavaRefactoringBundle.message("record.component.used.in.method.body.warning",
recordComponent.getName()));
}
if (pattern instanceof PsiTypeTestPattern typeTestPattern) {
PsiPatternVariable variable = typeTestPattern.getPatternVariable();
if (variable == null) return;
for (PsiReferenceExpression deconstructionReference : VariableAccessUtils.getVariableReferences(variable,
aClass.getContainingFile())) {
context.getContainingFile())) {
conflictDescriptions.putValue(deconstructionReference,
JavaRefactoringBundle.message("record.component.used.in.method.body.warning", recordComponent.getName()));
}
}
if (pattern instanceof PsiDeconstructionPattern deconstructionPattern) {
for (PsiPattern nestedDeconstructionPattern : deconstructionPattern.getDeconstructionList().getDeconstructionComponents()) {
collectDeconstructionRecordUsagesConflict(nestedDeconstructionPattern, aClass, conflictDescriptions, recordComponent);
PsiType psiType = deconstructionPattern.getTypeElement().getType();
PsiClass nestedRecord = PsiUtil.resolveClassInClassTypeOnly(psiType);
if (nestedRecord == null || !nestedRecord.isRecord()) return;
PsiDeconstructionList deconstructionList = deconstructionPattern.getDeconstructionList();
PsiPattern[] components = deconstructionList.getDeconstructionComponents();
if(components.length != nestedRecord.getRecordComponents().length) {
return;
}
for (int i = 0; i < components.length; i++) {
PsiPattern nestedDeconstructionPattern = components[i];
PsiRecordComponent nestedComponent = nestedRecord.getRecordComponents()[i];
collectDeconstructionRecordToDeleteUsagesConflict(nestedDeconstructionPattern, context, conflictDescriptions, nestedComponent);
}
}
}

View File

@@ -0,0 +1,18 @@
public class ConflictsSwitchNestedDeconstructionDifTypes {
public static void main(String[] args) {
final Point point = new Point(199, null);
point.foo(point);
}
public record Point(Object x<caret>, Point y) {
void foo(Object obj) {
switch (obj) {
case Point(Object x, Point(Integer x2, Point y2)) -> {
System.out.println("y2");
}
default -> {
System.out.println("default");
}
}
}
}
}

View File

@@ -1028,4 +1028,18 @@ public class ChangeSignatureTest extends ChangeSignatureBaseTest {
};
}, false);
}
public void testConflictsSwitchNestedDeconstructionDifTypes() {
try {
final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
final PsiType pointType = facade.getElementFactory().createTypeFromText("int", null);
doTest(null, null, null, method -> {
return new ParameterInfoImpl[]{
ParameterInfoImpl.create(0).withName("x").withType(pointType)
};
}, false);
fail("Conflict expected");
}
catch (BaseRefactoringProcessor.ConflictsInTestsException ignored) { }
}
}