mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-07 22:09:38 +07:00
Java: support safe delete for record components (IDEA-245145)
GitOrigin-RevId: 5eccf46c5e0cce0d63c5ac480ad8d180b1ef0fed
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1ce2fdbcb5
commit
81a6c7d02c
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.lang.java;
|
||||
|
||||
import com.intellij.lang.LanguageNamesValidation;
|
||||
@@ -38,7 +38,7 @@ public class JavaRefactoringSupportProvider extends JavaBaseRefactoringSupportPr
|
||||
public boolean isSafeDeleteAvailable(@NotNull PsiElement element) {
|
||||
return element instanceof PsiClass || element instanceof PsiMethod || element instanceof PsiField ||
|
||||
(element instanceof PsiParameter && ((PsiParameter)element).getDeclarationScope() instanceof PsiMethod) ||
|
||||
element instanceof PsiPackage || element instanceof PsiLocalVariable;
|
||||
element instanceof PsiPackage || element instanceof PsiLocalVariable || element instanceof PsiRecordComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import com.intellij.psi.impl.FindSuperElementsHelper;
|
||||
import com.intellij.psi.impl.light.LightRecordMethod;
|
||||
import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
|
||||
import com.intellij.psi.javadoc.PsiDocTag;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
@@ -94,9 +95,12 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
else if (element instanceof PsiField field) {
|
||||
insideDeletedCondition = findFieldUsages(field, usages, allElementsToDelete);
|
||||
}
|
||||
else if (element instanceof PsiRecordComponent component) {
|
||||
insideDeletedCondition = findRecordComponentUsages(component, allElementsToDelete, usages);
|
||||
}
|
||||
else if (element instanceof PsiParameter parameter) {
|
||||
LOG.assertTrue(parameter.getDeclarationScope() instanceof PsiMethod);
|
||||
findParameterUsages(parameter, usages);
|
||||
findParameterUsages(parameter, allElementsToDelete, usages);
|
||||
}
|
||||
else if (element instanceof PsiLocalVariable) {
|
||||
for (PsiReference reference : ReferencesSearch.search(element)) {
|
||||
@@ -230,6 +234,26 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
public Collection<PsiElement> getAdditionalElementsToDelete(@NotNull PsiElement element,
|
||||
@NotNull Collection<? extends PsiElement> allElementsToDelete,
|
||||
boolean askUser) {
|
||||
if (element instanceof PsiRecordComponent component) {
|
||||
PsiMethod method = JavaPsiRecordUtil.getAccessorForRecordComponent(component);
|
||||
List<PsiElement> additional = new ArrayList<>();
|
||||
if (method != null && !(method instanceof SyntheticElement) && !allElementsToDelete.contains(method)) {
|
||||
additional.add(method);
|
||||
}
|
||||
PsiClass recordClass = component.getContainingClass();
|
||||
assert recordClass != null;
|
||||
PsiMethod constructor = JavaPsiRecordUtil.findCanonicalConstructor(recordClass);
|
||||
if (constructor == null || constructor instanceof SyntheticElement) return additional;
|
||||
PsiRecordHeader header = recordClass.getRecordHeader();
|
||||
assert header != null;
|
||||
int index = ArrayUtil.indexOf(header.getRecordComponents(), component);
|
||||
if (index < 0) return additional;
|
||||
PsiParameter parameter = constructor.getParameterList().getParameter(index);
|
||||
if (parameter != null) {
|
||||
additional.add(parameter);
|
||||
}
|
||||
return additional;
|
||||
}
|
||||
if (element instanceof PsiField field) {
|
||||
Project project = element.getProject();
|
||||
String propertyName = JavaCodeStyleManager.getInstance(project).variableNameToPropertyName(field.getName(), VariableKind.FIELD);
|
||||
@@ -328,6 +352,22 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
return conflicts.values();
|
||||
}
|
||||
}
|
||||
else if (element instanceof PsiRecordComponent component) {
|
||||
PsiClass recordClass = component.getContainingClass();
|
||||
assert recordClass != null;
|
||||
PsiMethod constructor = JavaPsiRecordUtil.findCanonicalConstructor(recordClass);
|
||||
if (constructor != null) {
|
||||
PsiRecordHeader header = recordClass.getRecordHeader();
|
||||
assert header != null;
|
||||
int index = ArrayUtil.indexOf(header.getRecordComponents(), component);
|
||||
if (index >= 0) {
|
||||
PsiParameter parameter = constructor.getParameterList().getParameter(index);
|
||||
if(parameter != null) {
|
||||
return findConflicts(parameter, allElementsToDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -947,8 +987,42 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
: new SafeDeleteParameterCallHierarchyUsageInfo(called, calledParameter, caller, parameterInCaller);
|
||||
}
|
||||
|
||||
private static Condition<PsiElement> findRecordComponentUsages(PsiRecordComponent component,
|
||||
PsiElement @NotNull [] allElementsToDelete,
|
||||
List<? super UsageInfo> usages) {
|
||||
Condition <PsiElement> isInsideDeleted = getUsageInsideDeletedFilter(allElementsToDelete);
|
||||
PsiClass recordClass = component.getContainingClass();
|
||||
assert recordClass != null;
|
||||
PsiMethod constructor = JavaPsiRecordUtil.findCanonicalConstructor(recordClass);
|
||||
if (constructor != null) {
|
||||
PsiRecordHeader header = recordClass.getRecordHeader();
|
||||
assert header != null;
|
||||
int index = ArrayUtil.indexOf(header.getRecordComponents(), component);
|
||||
if (index < 0) return isInsideDeleted;
|
||||
ReferencesSearch.search(constructor).forEach(ref -> {
|
||||
PsiElement element = ref.getElement();
|
||||
if (!isInsideDeleted.test(element)) {
|
||||
JavaSafeDeleteDelegate safeDeleteDelegate = JavaSafeDeleteDelegate.EP.forLanguage(element.getLanguage());
|
||||
if (safeDeleteDelegate != null) {
|
||||
safeDeleteDelegate.createUsageInfoForParameter(ref, usages, component, index, component.isVarArgs());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
ReferencesSearch.search(component).forEach(ref -> {
|
||||
PsiElement element = ref.getElement();
|
||||
if (!isInsideDeleted.test(element)) {
|
||||
boolean javadoc = element instanceof PsiDocParamRef;
|
||||
PsiElement parent = element.getParent();
|
||||
usages.add(parent instanceof PsiAssignmentExpression assignment && element == assignment.getLExpression()
|
||||
? new SafeDeleteFieldWriteReference(assignment, component)
|
||||
: new SafeDeleteReferenceJavaDeleteUsageInfo(javadoc ? parent : element, component, javadoc));
|
||||
}
|
||||
});
|
||||
return isInsideDeleted;
|
||||
}
|
||||
|
||||
private static void findParameterUsages(@NotNull PsiParameter parameter, @NotNull List<? super UsageInfo> usages) {
|
||||
private static void findParameterUsages(@NotNull PsiParameter parameter, PsiElement @NotNull [] allElementsToDelete, @NotNull List<? super UsageInfo> usages) {
|
||||
PsiMethod method = (PsiMethod)parameter.getDeclarationScope();
|
||||
int parameterIndex = method.getParameterList().getParameterIndex(parameter);
|
||||
if (parameterIndex < 0) return;
|
||||
@@ -976,6 +1050,17 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(docTag, parameter, true));
|
||||
return true;
|
||||
}
|
||||
PsiElement parent = PsiUtil.skipParenthesizedExprUp(element.getParent());
|
||||
if (parent instanceof PsiAssignmentExpression assignment && PsiTreeUtil.isAncestor(assignment.getRExpression(), element, false)) {
|
||||
PsiExpression lhs = assignment.getLExpression();
|
||||
if (lhs instanceof PsiReferenceExpression ref) {
|
||||
PsiElement target = ref.resolve();
|
||||
if (target instanceof PsiField field) {
|
||||
PsiRecordComponent component = JavaPsiRecordUtil.getComponentForField(field);
|
||||
if (component != null && isInside(component, allElementsToDelete)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isSafeDelete = false;
|
||||
if (element.getParent().getParent() instanceof PsiMethodCallExpression call) {
|
||||
|
||||
@@ -1,43 +1,26 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.refactoring.safeDelete.usageInfo;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class SafeDeleteFieldWriteReference extends SafeDeleteReferenceUsageInfo {
|
||||
private final PsiAssignmentExpression myExpression;
|
||||
|
||||
public SafeDeleteFieldWriteReference(PsiAssignmentExpression expr, PsiField referencedElement) {
|
||||
public SafeDeleteFieldWriteReference(PsiAssignmentExpression expr, PsiMember referencedElement) {
|
||||
super(expr, referencedElement, safeRemoveRHS(expr));
|
||||
myExpression = expr;
|
||||
}
|
||||
|
||||
private static boolean safeRemoveRHS(PsiAssignmentExpression expression) {
|
||||
final PsiExpression rExpression = expression.getRExpression();
|
||||
final PsiElement parent = expression.getParent();
|
||||
return RefactoringUtil.verifySafeCopyExpression(rExpression) == RefactoringUtil.EXPR_COPY_SAFE
|
||||
&& parent instanceof PsiExpressionStatement
|
||||
&& ((PsiExpressionStatement) parent).getExpression() == expression;
|
||||
&& parent instanceof PsiExpressionStatement statement
|
||||
&& statement.getExpression() == expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteElement() throws IncorrectOperationException {
|
||||
myExpression.getParent().delete();
|
||||
public void deleteElement() {
|
||||
PsiElement element = getElement();
|
||||
if (element != null) element.getParent().delete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user