diff --git a/plugin/src/main/java/com/intellij/java/impl/codeInsight/editorActions/CopyPasteReferenceProcessor.java b/plugin/src/main/java/com/intellij/java/impl/codeInsight/editorActions/CopyPasteReferenceProcessor.java index d735f74d0..3ac5be19e 100644 --- a/plugin/src/main/java/com/intellij/java/impl/codeInsight/editorActions/CopyPasteReferenceProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/codeInsight/editorActions/CopyPasteReferenceProcessor.java @@ -15,25 +15,26 @@ */ package com.intellij.java.impl.codeInsight.editorActions; -import consulo.language.editor.CodeInsightSettings; -import consulo.language.editor.util.CollectHighlightsUtil; -import consulo.ide.impl.idea.codeInsight.editorActions.CopyPastePostProcessor; import com.intellij.java.language.psi.JavaPsiFacade; import com.intellij.java.language.psi.PsiClass; import com.intellij.java.language.psi.PsiClassOwner; -import consulo.application.ApplicationManager; -import consulo.document.Document; +import consulo.annotation.access.RequiredReadAction; +import consulo.application.Application; import consulo.codeEditor.Editor; +import consulo.document.Document; import consulo.document.RangeMarker; -import consulo.project.DumbService; -import consulo.project.Project; -import consulo.util.lang.Comparing; -import consulo.util.lang.ref.Ref; import consulo.document.util.TextRange; +import consulo.ide.impl.idea.codeInsight.editorActions.CopyPastePostProcessor; +import consulo.language.editor.CodeInsightSettings; +import consulo.language.editor.util.CollectHighlightsUtil; import consulo.language.psi.*; -import consulo.util.collection.ArrayUtil; import consulo.logging.Logger; - +import consulo.project.DumbService; +import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; +import consulo.util.collection.ArrayUtil; +import consulo.util.lang.Comparing; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -41,180 +42,203 @@ import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; public abstract class CopyPasteReferenceProcessor extends CopyPastePostProcessor { - private static final Logger LOG = Logger.getInstance(CopyPasteReferenceProcessor.class); - - @Nonnull - @Override - public List collectTransferableData(PsiFile file, final Editor editor, final int[] startOffsets, - final int[] endOffsets) { - if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.NO) { - return Collections.emptyList(); - } + private static final Logger LOG = Logger.getInstance(CopyPasteReferenceProcessor.class); + + @Nonnull + @Override + @RequiredReadAction + public List collectTransferableData( + PsiFile file, + Editor editor, + int[] startOffsets, + int[] endOffsets + ) { + if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.NO) { + return Collections.emptyList(); + } - if (file instanceof PsiCompiledFile) { - file = ((PsiCompiledFile) file).getDecompiledPsiFile(); - } - if (!(file instanceof PsiClassOwner)) { - return Collections.emptyList(); - } + if (file instanceof PsiCompiledFile) { + file = ((PsiCompiledFile)file).getDecompiledPsiFile(); + } + if (!(file instanceof PsiClassOwner)) { + return Collections.emptyList(); + } - final ArrayList array = new ArrayList(); - for (int j = 0; j < startOffsets.length; j++) { - final int startOffset = startOffsets[j]; - for (final PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffset, endOffsets[j])) { - addReferenceData(file, startOffset, element, array); - } - } + ArrayList array = new ArrayList<>(); + for (int j = 0; j < startOffsets.length; j++) { + int startOffset = startOffsets[j]; + for (PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffset, endOffsets[j])) { + addReferenceData(file, startOffset, element, array); + } + } - if (array.isEmpty()) { - return Collections.emptyList(); - } + if (array.isEmpty()) { + return Collections.emptyList(); + } - return Collections.singletonList(new ReferenceTransferableData(array.toArray(new ReferenceData[array.size()]))); - } + return Collections.singletonList(new ReferenceTransferableData(array.toArray(new ReferenceData[array.size()]))); + } - protected abstract void addReferenceData(PsiFile file, int startOffset, PsiElement element, ArrayList to); + protected abstract void addReferenceData(PsiFile file, int startOffset, PsiElement element, ArrayList to); + + @Nonnull + @Override + public List extractTransferableData(Transferable content) { + ReferenceTransferableData referenceData = null; + if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE != CodeInsightSettings.NO) { + try { + DataFlavor flavor = ReferenceData.getDataFlavor(); + if (flavor != null) { + referenceData = (ReferenceTransferableData)content.getTransferData(flavor); + } + } + catch (UnsupportedFlavorException | IOException ignored) { + } + } - @Nonnull - @Override - public List extractTransferableData(final Transferable content) { - ReferenceTransferableData referenceData = null; - if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE != CodeInsightSettings.NO) { - try { - final DataFlavor flavor = ReferenceData.getDataFlavor(); - if (flavor != null) { - referenceData = (ReferenceTransferableData) content.getTransferData(flavor); + if (referenceData != null) { // copy to prevent changing of original by convertLineSeparators + return Collections.singletonList(referenceData.clone()); } - } catch (UnsupportedFlavorException ignored) { - } catch (IOException ignored) { - } - } - if (referenceData != null) { // copy to prevent changing of original by convertLineSeparators - return Collections.singletonList(referenceData.clone()); + return Collections.emptyList(); } - return Collections.emptyList(); - } + @Override + @RequiredUIAccess + public void processTransferableData( + Project project, + Editor editor, + RangeMarker bounds, + int caretOffset, + SimpleReference indented, + List values + ) { + if (DumbService.getInstance(project).isDumb()) { + return; + } + Document document = editor.getDocument(); + PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); - @Override - public void processTransferableData(final Project project, final Editor editor, final RangeMarker bounds, int caretOffset, - Ref indented, final List values) { - if (DumbService.getInstance(project).isDumb()) { - return; - } - final Document document = editor.getDocument(); - final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); + if (!(file instanceof PsiClassOwner)) { + return; + } - if (!(file instanceof PsiClassOwner)) { - return; + PsiDocumentManager.getInstance(project).commitAllDocuments(); + assert values.size() == 1; + ReferenceData[] referenceData = values.get(0).getData(); + TRef[] refs = findReferencesToRestore(file, bounds, referenceData); + if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.ASK) { + askReferencesToRestore(project, refs, referenceData); + } + PsiDocumentManager.getInstance(project).commitAllDocuments(); + Application.get().runWriteAction(() -> restoreReferences(referenceData, refs)); } - PsiDocumentManager.getInstance(project).commitAllDocuments(); - assert values.size() == 1; - final ReferenceData[] referenceData = values.get(0).getData(); - final TRef[] refs = findReferencesToRestore(file, bounds, referenceData); - if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.ASK) { - askReferencesToRestore(project, refs, referenceData); + @RequiredReadAction + protected static void addReferenceData( + PsiElement element, + ArrayList array, + int startOffset, + String qClassName, + @Nullable String staticMemberName + ) { + TextRange range = element.getTextRange(); + array.add(new ReferenceData( + range.getStartOffset() - startOffset, + range.getEndOffset() - startOffset, + qClassName, + staticMemberName + )); } - PsiDocumentManager.getInstance(project).commitAllDocuments(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - restoreReferences(referenceData, refs); - } - }); - } - - protected static void addReferenceData(final PsiElement element, final ArrayList array, final int startOffset, - final String qClassName, @Nullable final String staticMemberName) { - final TextRange range = element.getTextRange(); - array.add(new ReferenceData(range.getStartOffset() - startOffset, range.getEndOffset() - startOffset, qClassName, staticMemberName)); - } - - protected abstract TRef[] findReferencesToRestore(PsiFile file, RangeMarker bounds, ReferenceData[] referenceData); - - protected PsiElement resolveReferenceIgnoreOverriding(PsiPolyVariantReference reference) { - PsiElement referent = reference.resolve(); - if (referent == null) { - final ResolveResult[] results = reference.multiResolve(true); - if (results.length > 0) { - referent = results[0].getElement(); - } - } - return referent; - } - - protected abstract void restoreReferences(ReferenceData[] referenceData, TRef[] refs); - - private static void askReferencesToRestore(Project project, PsiElement[] refs, ReferenceData[] referenceData) { - PsiManager manager = PsiManager.getInstance(project); - - ArrayList array = new ArrayList(); - Object[] refObjects = new Object[refs.length]; - for (int i = 0; i < referenceData.length; i++) { - PsiElement ref = refs[i]; - if (ref != null) { - LOG.assertTrue(ref.isValid()); - ReferenceData data = referenceData[i]; - PsiClass refClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(data.qClassName, ref.getResolveScope()); - if (refClass == null) { - continue; - } - Object refObject = refClass; - if (data.staticMemberName != null) { - //Show static members as Strings - refObject = refClass.getQualifiedName() + "." + data.staticMemberName; - } - refObjects[i] = refObject; + protected abstract TRef[] findReferencesToRestore(PsiFile file, RangeMarker bounds, ReferenceData[] referenceData); - if (!array.contains(refObject)) { - array.add(refObject); + @RequiredReadAction + protected PsiElement resolveReferenceIgnoreOverriding(PsiPolyVariantReference reference) { + PsiElement referent = reference.resolve(); + if (referent == null) { + ResolveResult[] results = reference.multiResolve(true); + if (results.length > 0) { + referent = results[0].getElement(); + } } - } - } - if (array.isEmpty()) { - return; + return referent; } - Object[] selectedObjects = ArrayUtil.toObjectArray(array); - Arrays.sort(selectedObjects, new Comparator() { - @Override - public int compare(Object o1, Object o2) { - String fqName1 = getFQName(o1); - String fqName2 = getFQName(o2); - return fqName1.compareToIgnoreCase(fqName2); - } - }); - - RestoreReferencesDialog dialog = new RestoreReferencesDialog(project, selectedObjects); - dialog.show(); - selectedObjects = dialog.getSelectedElements(); - - for (int i = 0; i < referenceData.length; i++) { - PsiElement ref = refs[i]; - if (ref != null) { - LOG.assertTrue(ref.isValid()); - Object refObject = refObjects[i]; - boolean found = false; - for (Object selected : selectedObjects) { - if (Comparing.equal(refObject, selected)) { - found = true; - break; - } + protected abstract void restoreReferences(ReferenceData[] referenceData, TRef[] refs); + + @RequiredUIAccess + private static void askReferencesToRestore(Project project, PsiElement[] refs, ReferenceData[] referenceData) { + PsiManager manager = PsiManager.getInstance(project); + + ArrayList array = new ArrayList<>(); + Object[] refObjects = new Object[refs.length]; + for (int i = 0; i < referenceData.length; i++) { + PsiElement ref = refs[i]; + if (ref != null) { + LOG.assertTrue(ref.isValid()); + ReferenceData data = referenceData[i]; + PsiClass refClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(data.qClassName, ref.getResolveScope()); + if (refClass == null) { + continue; + } + + Object refObject = refClass; + if (data.staticMemberName != null) { + //Show static members as Strings + refObject = refClass.getQualifiedName() + "." + data.staticMemberName; + } + refObjects[i] = refObject; + + if (!array.contains(refObject)) { + array.add(refObject); + } + } } - if (!found) { - refs[i] = null; + if (array.isEmpty()) { + return; + } + + Object[] selectedObjects = ArrayUtil.toObjectArray(array); + Arrays.sort( + selectedObjects, + (o1, o2) -> { + String fqName1 = getFQName(o1); + String fqName2 = getFQName(o2); + return fqName1.compareToIgnoreCase(fqName2); + } + ); + + RestoreReferencesDialog dialog = new RestoreReferencesDialog(project, selectedObjects); + dialog.show(); + selectedObjects = dialog.getSelectedElements(); + + for (int i = 0; i < referenceData.length; i++) { + PsiElement ref = refs[i]; + if (ref != null) { + LOG.assertTrue(ref.isValid()); + Object refObject = refObjects[i]; + boolean found = false; + for (Object selected : selectedObjects) { + if (Comparing.equal(refObject, selected)) { + found = true; + break; + } + } + if (!found) { + refs[i] = null; + } + } } - } } - } - private static String getFQName(Object element) { - return element instanceof PsiClass ? ((PsiClass) element).getQualifiedName() : (String) element; - } + private static String getFQName(Object element) { + return element instanceof PsiClass psiClass ? psiClass.getQualifiedName() : (String)element; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java index 345f1d302..cea397bfb 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java @@ -18,6 +18,7 @@ import com.intellij.java.impl.refactoring.changeSignature.ChangeSignatureUtil; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiUtil; +import consulo.annotation.access.RequiredReadAction; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.editor.refactoring.ui.RefactoringUIUtil; import consulo.language.psi.PsiElement; @@ -30,11 +31,12 @@ import consulo.localHistory.LocalHistoryAction; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.ArrayUtil; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.*; @@ -43,192 +45,206 @@ * @author dsl */ public class ChangeClassSignatureProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(ChangeClassSignatureProcessor.class); - private PsiClass myClass; - private final TypeParameterInfo[] myNewSignature; - - public ChangeClassSignatureProcessor(Project project, PsiClass aClass, TypeParameterInfo[] newSignature) { - super(project); - myClass = aClass; - myNewSignature = newSignature; - } - - protected void refreshElements(PsiElement[] elements) { - LOG.assertTrue(elements.length == 1); - LOG.assertTrue(elements[0] instanceof PsiClass); - myClass = (PsiClass)elements[0]; - } - - protected String getCommandName() { - return ChangeClassSignatureDialog.REFACTORING_NAME; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new ChangeClassSigntaureViewDescriptor(myClass); - } - - @Override - protected boolean preprocessUsages(Ref refUsages) { - final MultiMap conflicts = new MultiMap(); - - final PsiTypeParameter[] parameters = myClass.getTypeParameters(); - final Map infos = new HashMap(); - for (TypeParameterInfo info : myNewSignature) { - final String newName = info.isForExistingParameter() ? parameters[info.getOldParameterIndex()].getName() : info.getNewName(); - TypeParameterInfo existing = infos.get(newName); - if (existing != null) { - conflicts.putValue(myClass, RefactoringUIUtil.getDescription(myClass, false) + " already contains type parameter " + newName); - } - infos.put(newName, info); + private static final Logger LOG = Logger.getInstance(ChangeClassSignatureProcessor.class); + private PsiClass myClass; + private final TypeParameterInfo[] myNewSignature; + + public ChangeClassSignatureProcessor(Project project, PsiClass aClass, TypeParameterInfo[] newSignature) { + super(project); + myClass = aClass; + myNewSignature = newSignature; } - return showConflicts(conflicts, refUsages.get()); - } - - @Nonnull - protected UsageInfo[] findUsages() { - GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject); - List result = new ArrayList(); - - boolean hadTypeParameters = myClass.hasTypeParameters(); - for (final PsiReference reference : ReferencesSearch.search(myClass, projectScope, false)) { - if (reference.getElement() instanceof PsiJavaCodeReferenceElement) { - PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)reference.getElement(); - PsiElement parent = referenceElement.getParent(); - if (parent instanceof PsiTypeElement && parent.getParent() instanceof PsiInstanceOfExpression) continue; - if (parent instanceof PsiTypeElement || parent instanceof PsiNewExpression || parent instanceof PsiAnonymousClass || - parent instanceof PsiReferenceList) { - if (!hadTypeParameters || referenceElement.getTypeParameters().length > 0) { - result.add(new UsageInfo(referenceElement)); - } - } - } + + @Override + protected void refreshElements(PsiElement[] elements) { + LOG.assertTrue(elements.length == 1); + LOG.assertTrue(elements[0] instanceof PsiClass); + myClass = (PsiClass)elements[0]; } - return result.toArray(new UsageInfo[result.size()]); - } - protected void performRefactoring(UsageInfo[] usages) { - LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName()); - try { - doRefactoring(usages); + @Nonnull + @Override + protected String getCommandName() { + return ChangeClassSignatureDialog.REFACTORING_NAME; } - catch (IncorrectOperationException e) { - LOG.error(e); + + @Nonnull + @Override + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new ChangeClassSigntaureViewDescriptor(myClass); } - finally { - a.finish(); + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + MultiMap conflicts = new MultiMap<>(); + + PsiTypeParameter[] parameters = myClass.getTypeParameters(); + Map infos = new HashMap<>(); + for (TypeParameterInfo info : myNewSignature) { + String newName = info.isForExistingParameter() ? parameters[info.getOldParameterIndex()].getName() : info.getNewName(); + TypeParameterInfo existing = infos.get(newName); + if (existing != null) { + conflicts.putValue( + myClass, + RefactoringUIUtil.getDescription(myClass, false) + " already contains type parameter " + newName + ); + } + infos.put(newName, info); + } + return showConflicts(conflicts, refUsages.get()); } - } - private void doRefactoring(UsageInfo[] usages) throws IncorrectOperationException { - final PsiTypeParameter[] typeParameters = myClass.getTypeParameters(); - final boolean[] toRemoveParms = detectRemovedParameters(typeParameters); + @Nonnull + @Override + @RequiredReadAction + protected UsageInfo[] findUsages() { + GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject); + List result = new ArrayList<>(); + + boolean hadTypeParameters = myClass.hasTypeParameters(); + for (PsiReference reference : ReferencesSearch.search(myClass, projectScope, false)) { + if (reference.getElement() instanceof PsiJavaCodeReferenceElement referenceElement) { + PsiElement parent = referenceElement.getParent(); + if (parent instanceof PsiTypeElement typeElem && typeElem.getParent() instanceof PsiInstanceOfExpression) { + continue; + } + if (parent instanceof PsiTypeElement || parent instanceof PsiNewExpression + || parent instanceof PsiAnonymousClass || parent instanceof PsiReferenceList) { + if (!hadTypeParameters || referenceElement.getTypeParameters().length > 0) { + result.add(new UsageInfo(referenceElement)); + } + } + } + } + return result.toArray(new UsageInfo[result.size()]); + } - for (final UsageInfo usage : usages) { - LOG.assertTrue(usage.getElement() instanceof PsiJavaCodeReferenceElement); - processUsage(usage, typeParameters, toRemoveParms); + @Override + protected void performRefactoring(@Nonnull UsageInfo[] usages) { + LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName()); + try { + doRefactoring(usages); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + finally { + a.finish(); + } } - final Map supersMap = new HashMap(); - myClass.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitTypeElement(PsiTypeElement typeElement) { - super.visitTypeElement(typeElement); - final PsiType type = typeElement.getType(); - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass instanceof PsiTypeParameter) { - final int i = ArrayUtil.find(typeParameters, psiClass); - if ( i >= 0 && i < toRemoveParms.length && toRemoveParms[i]) { - supersMap.put(typeElement, psiClass.getSuperClass()); - } + + private void doRefactoring(UsageInfo[] usages) throws IncorrectOperationException { + PsiTypeParameter[] typeParameters = myClass.getTypeParameters(); + boolean[] toRemoveParms = detectRemovedParameters(typeParameters); + + for (UsageInfo usage : usages) { + LOG.assertTrue(usage.getElement() instanceof PsiJavaCodeReferenceElement); + processUsage(usage, typeParameters, toRemoveParms); + } + Map supersMap = new HashMap<>(); + myClass.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitTypeElement(@Nonnull PsiTypeElement typeElement) { + super.visitTypeElement(typeElement); + if (PsiUtil.resolveClassInType(typeElement.getType()) instanceof PsiTypeParameter typeParam) { + int i = ArrayUtil.find(typeParameters, typeParam); + if (i >= 0 && i < toRemoveParms.length && toRemoveParms[i]) { + supersMap.put(typeElement, typeParam.getSuperClass()); + } + } + } + }); + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); + for (Map.Entry classEntry : supersMap.entrySet()) { + classEntry.getKey().replace(elementFactory.createTypeElement(elementFactory.createType(classEntry.getValue()))); } - } - }); - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - for (Map.Entry classEntry : supersMap.entrySet()) { - classEntry.getKey().replace(elementFactory.createTypeElement(elementFactory.createType(classEntry.getValue()))); + changeClassSignature(typeParameters, toRemoveParms); } - changeClassSignature(typeParameters, toRemoveParms); - } - - private void changeClassSignature(final PsiTypeParameter[] originalTypeParameters, boolean[] toRemoveParms) - throws IncorrectOperationException { - PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); - List newTypeParameters = new ArrayList(); - for (final TypeParameterInfo info : myNewSignature) { - int oldIndex = info.getOldParameterIndex(); - if (oldIndex >= 0) { - newTypeParameters.add(originalTypeParameters[oldIndex]); - } - else { - newTypeParameters.add(factory.createTypeParameterFromText(info.getNewName(), null)); - } + + private void changeClassSignature(PsiTypeParameter[] originalTypeParameters, boolean[] toRemoveParms) + throws IncorrectOperationException { + PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); + List newTypeParameters = new ArrayList<>(); + for (TypeParameterInfo info : myNewSignature) { + int oldIndex = info.getOldParameterIndex(); + if (oldIndex >= 0) { + newTypeParameters.add(originalTypeParameters[oldIndex]); + } + else { + newTypeParameters.add(factory.createTypeParameterFromText(info.getNewName(), null)); + } + } + ChangeSignatureUtil.synchronizeList(myClass.getTypeParameterList(), newTypeParameters, TypeParameterList.INSTANCE, toRemoveParms); } - ChangeSignatureUtil.synchronizeList(myClass.getTypeParameterList(), newTypeParameters, TypeParameterList.INSTANCE, toRemoveParms); - } - - private boolean[] detectRemovedParameters(final PsiTypeParameter[] originaltypeParameters) { - final boolean[] toRemoveParms = new boolean[originaltypeParameters.length]; - Arrays.fill(toRemoveParms, true); - for (final TypeParameterInfo info : myNewSignature) { - int oldParameterIndex = info.getOldParameterIndex(); - if (oldParameterIndex >= 0) { - toRemoveParms[oldParameterIndex] = false; - } + + private boolean[] detectRemovedParameters(PsiTypeParameter[] originaltypeParameters) { + boolean[] toRemoveParms = new boolean[originaltypeParameters.length]; + Arrays.fill(toRemoveParms, true); + for (TypeParameterInfo info : myNewSignature) { + int oldParameterIndex = info.getOldParameterIndex(); + if (oldParameterIndex >= 0) { + toRemoveParms[oldParameterIndex] = false; + } + } + return toRemoveParms; } - return toRemoveParms; - } - - private void processUsage(final UsageInfo usage, final PsiTypeParameter[] originalTypeParameters, final boolean[] toRemoveParms) - throws IncorrectOperationException { - PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); - PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)usage.getElement(); - PsiSubstitutor usageSubstitutor = determineUsageSubstitutor(referenceElement); - - PsiReferenceParameterList referenceParameterList = referenceElement.getParameterList(); - PsiTypeElement[] oldValues = referenceParameterList.getTypeParameterElements(); - if (oldValues.length != originalTypeParameters.length) return; - List newValues = new ArrayList(); - for (final TypeParameterInfo info : myNewSignature) { - int oldIndex = info.getOldParameterIndex(); - if (oldIndex >= 0) { - newValues.add(oldValues[oldIndex]); - } - else { - PsiType type = info.getDefaultValue().getType(myClass.getLBrace(), PsiManager.getInstance(myProject)); - - PsiTypeElement newValue = factory.createTypeElement(usageSubstitutor.substitute(type)); - newValues.add(newValue); - } + + private void processUsage(UsageInfo usage, PsiTypeParameter[] originalTypeParameters, boolean[] toRemoveParms) + throws IncorrectOperationException { + PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); + PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)usage.getElement(); + PsiSubstitutor usageSubstitutor = determineUsageSubstitutor(referenceElement); + + PsiReferenceParameterList referenceParameterList = referenceElement.getParameterList(); + PsiTypeElement[] oldValues = referenceParameterList.getTypeParameterElements(); + if (oldValues.length != originalTypeParameters.length) { + return; + } + List newValues = new ArrayList<>(); + for (TypeParameterInfo info : myNewSignature) { + int oldIndex = info.getOldParameterIndex(); + if (oldIndex >= 0) { + newValues.add(oldValues[oldIndex]); + } + else { + PsiType type = info.getDefaultValue().getType(myClass.getLBrace(), PsiManager.getInstance(myProject)); + + PsiTypeElement newValue = factory.createTypeElement(usageSubstitutor.substitute(type)); + newValues.add(newValue); + } + } + ChangeSignatureUtil.synchronizeList(referenceParameterList, newValues, ReferenceParameterList.INSTANCE, toRemoveParms); } - ChangeSignatureUtil.synchronizeList(referenceParameterList, newValues, ReferenceParameterList.INSTANCE, toRemoveParms); - } - - private PsiSubstitutor determineUsageSubstitutor(PsiJavaCodeReferenceElement referenceElement) { - PsiType[] typeArguments = referenceElement.getTypeParameters(); - PsiSubstitutor usageSubstitutor = PsiSubstitutor.EMPTY; - PsiTypeParameter[] typeParameters = myClass.getTypeParameters(); - if (typeParameters.length == typeArguments.length) { - for (int i = 0; i < typeParameters.length; i++) { - usageSubstitutor = usageSubstitutor.put(typeParameters[i], typeArguments[i]); - } + + private PsiSubstitutor determineUsageSubstitutor(PsiJavaCodeReferenceElement referenceElement) { + PsiType[] typeArguments = referenceElement.getTypeParameters(); + PsiSubstitutor usageSubstitutor = PsiSubstitutor.EMPTY; + PsiTypeParameter[] typeParameters = myClass.getTypeParameters(); + if (typeParameters.length == typeArguments.length) { + for (int i = 0; i < typeParameters.length; i++) { + usageSubstitutor = usageSubstitutor.put(typeParameters[i], typeArguments[i]); + } + } + return usageSubstitutor; } - return usageSubstitutor; - } - private static class ReferenceParameterList implements ChangeSignatureUtil.ChildrenGenerator { - private static final ReferenceParameterList INSTANCE = new ReferenceParameterList(); + private static class ReferenceParameterList + implements ChangeSignatureUtil.ChildrenGenerator { + private static final ReferenceParameterList INSTANCE = new ReferenceParameterList(); - public List getChildren(PsiReferenceParameterList list) { - return Arrays.asList(list.getTypeParameterElements()); + @Override + public List getChildren(PsiReferenceParameterList list) { + return Arrays.asList(list.getTypeParameterElements()); + } } - } - private static class TypeParameterList implements ChangeSignatureUtil.ChildrenGenerator { - private static final TypeParameterList INSTANCE = new TypeParameterList(); + private static class TypeParameterList implements ChangeSignatureUtil.ChildrenGenerator { + private static final TypeParameterList INSTANCE = new TypeParameterList(); - public List getChildren(PsiTypeParameterList psiTypeParameterList) { - return Arrays.asList(psiTypeParameterList.getTypeParameters()); + @Override + public List getChildren(PsiTypeParameterList psiTypeParameterList) { + return Arrays.asList(psiTypeParameterList.getTypeParameters()); + } } - } - } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureProcessor.java index a56da6d09..c07e0bebb 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureProcessor.java @@ -44,302 +44,312 @@ import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import java.util.*; public class ChangeSignatureProcessor extends ChangeSignatureProcessorBase { - private static final Logger LOG = Logger.getInstance(ChangeSignatureProcessor.class); + private static final Logger LOG = Logger.getInstance(ChangeSignatureProcessor.class); - public ChangeSignatureProcessor( - Project project, - PsiMethod method, - final boolean generateDelegate, - @PsiModifier.ModifierConstant String newVisibility, - String newName, - PsiType newType, - @Nonnull ParameterInfoImpl[] parameterInfo - ) { - this( - project, - method, - generateDelegate, - newVisibility, - newName, - newType != null ? CanonicalTypes.createTypeWrapper(newType) : null, - parameterInfo, - null, - null, - null - ); - } + public ChangeSignatureProcessor( + Project project, + PsiMethod method, + final boolean generateDelegate, + @PsiModifier.ModifierConstant String newVisibility, + String newName, + PsiType newType, + @Nonnull ParameterInfoImpl[] parameterInfo + ) { + this( + project, + method, + generateDelegate, + newVisibility, + newName, + newType != null ? CanonicalTypes.createTypeWrapper(newType) : null, + parameterInfo, + null, + null, + null + ); + } + + public ChangeSignatureProcessor( + Project project, + PsiMethod method, + final boolean generateDelegate, + @PsiModifier.ModifierConstant String newVisibility, + String newName, + PsiType newType, + ParameterInfoImpl[] parameterInfo, + ThrownExceptionInfo[] exceptionInfos + ) { + this( + project, + method, + generateDelegate, + newVisibility, + newName, + newType != null ? CanonicalTypes.createTypeWrapper(newType) : null, + parameterInfo, + exceptionInfos, + null, + null + ); + } - public ChangeSignatureProcessor( - Project project, - PsiMethod method, - final boolean generateDelegate, - @PsiModifier.ModifierConstant String newVisibility, - String newName, - PsiType newType, - ParameterInfoImpl[] parameterInfo, - ThrownExceptionInfo[] exceptionInfos - ) { - this( - project, - method, - generateDelegate, - newVisibility, - newName, - newType != null ? CanonicalTypes.createTypeWrapper(newType) : null, - parameterInfo, - exceptionInfos, - null, - null - ); - } + public ChangeSignatureProcessor( + Project project, + PsiMethod method, + boolean generateDelegate, + @PsiModifier.ModifierConstant String newVisibility, + String newName, + CanonicalTypes.Type newType, + @Nonnull ParameterInfoImpl[] parameterInfo, + ThrownExceptionInfo[] thrownExceptions, + Set propagateParametersMethods, + Set propagateExceptionsMethods + ) { + this( + project, + generateChangeInfo( + method, + generateDelegate, + newVisibility, + newName, + newType, + parameterInfo, + thrownExceptions, + propagateParametersMethods, + propagateExceptionsMethods + ) + ); + } - public ChangeSignatureProcessor( - Project project, - PsiMethod method, - boolean generateDelegate, - @PsiModifier.ModifierConstant String newVisibility, - String newName, - CanonicalTypes.Type newType, - @Nonnull ParameterInfoImpl[] parameterInfo, - ThrownExceptionInfo[] thrownExceptions, - Set propagateParametersMethods, - Set propagateExceptionsMethods - ) { - this( - project, - generateChangeInfo( - method, - generateDelegate, - newVisibility, - newName, - newType, - parameterInfo, - thrownExceptions, - propagateParametersMethods, - propagateExceptionsMethods - ) - ); - } + public ChangeSignatureProcessor(Project project, final JavaChangeInfo changeInfo) { + super(project, changeInfo); + LOG.assertTrue(myChangeInfo.getMethod().isValid()); + } - public ChangeSignatureProcessor(Project project, final JavaChangeInfo changeInfo) { - super(project, changeInfo); - LOG.assertTrue(myChangeInfo.getMethod().isValid()); - } + private static JavaChangeInfo generateChangeInfo( + PsiMethod method, + boolean generateDelegate, + @PsiModifier.ModifierConstant String newVisibility, + String newName, + CanonicalTypes.Type newType, + @Nonnull ParameterInfoImpl[] parameterInfo, + ThrownExceptionInfo[] thrownExceptions, + Set propagateParametersMethods, + Set propagateExceptionsMethods + ) { + Set myPropagateParametersMethods = propagateParametersMethods != null ? propagateParametersMethods : new HashSet<>(); + Set myPropagateExceptionsMethods = propagateExceptionsMethods != null ? propagateExceptionsMethods : new HashSet<>(); - private static JavaChangeInfo generateChangeInfo( - PsiMethod method, - boolean generateDelegate, - @PsiModifier.ModifierConstant String newVisibility, - String newName, - CanonicalTypes.Type newType, - @Nonnull ParameterInfoImpl[] parameterInfo, - ThrownExceptionInfo[] thrownExceptions, - Set propagateParametersMethods, - Set propagateExceptionsMethods - ) { - Set myPropagateParametersMethods = propagateParametersMethods != null ? propagateParametersMethods : new HashSet<>(); - Set myPropagateExceptionsMethods = propagateExceptionsMethods != null ? propagateExceptionsMethods : new HashSet<>(); + LOG.assertTrue(method.isValid()); + if (newVisibility == null) { + newVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList()); + } - LOG.assertTrue(method.isValid()); - if (newVisibility == null) { - newVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList()); + return new JavaChangeInfoImpl( + newVisibility, + method, + newName, + newType, + parameterInfo, + thrownExceptions, + generateDelegate, + myPropagateParametersMethods, + myPropagateExceptionsMethods + ); } - return new JavaChangeInfoImpl( - newVisibility, - method, - newName, - newType, - parameterInfo, - thrownExceptions, - generateDelegate, - myPropagateParametersMethods, - myPropagateExceptionsMethods - ); - } + @Override + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new ChangeSignatureViewDescriptor(getChangeInfo().getMethod()); + } - @Override - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { - return new ChangeSignatureViewDescriptor(getChangeInfo().getMethod()); - } + @Override + public JavaChangeInfoImpl getChangeInfo() { + return (JavaChangeInfoImpl)super.getChangeInfo(); + } - @Override - public JavaChangeInfoImpl getChangeInfo() { - return (JavaChangeInfoImpl) super.getChangeInfo(); - } + @Override + protected void refreshElements(PsiElement[] elements) { + boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod; + LOG.assertTrue(condition); + getChangeInfo().updateMethod((PsiMethod)elements[0]); + } - @Override - protected void refreshElements(PsiElement[] elements) { - boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod; - LOG.assertTrue(condition); - getChangeInfo().updateMethod((PsiMethod) elements[0]); - } + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + for (ChangeSignatureUsageProcessor processor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) { + if (processor instanceof ChangeSignatureUsageProcessorEx changeSignatureUsageProcessorEx + && changeSignatureUsageProcessorEx.setupDefaultValues(myChangeInfo, refUsages, myProject)) { + return false; + } + } + MultiMap conflictDescriptions = new MultiMap<>(); + for (ChangeSignatureUsageProcessor usageProcessor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) { + final MultiMap conflicts = usageProcessor.findConflicts(myChangeInfo, refUsages); + for (PsiElement key : conflicts.keySet()) { + Collection collection = conflictDescriptions.get(key); + if (collection.size() == 0) { + collection = new HashSet<>(); + } + collection.addAll(conflicts.get(key)); + conflictDescriptions.put(key, collection); + } + } - @Override - @RequiredUIAccess - protected boolean preprocessUsages(@Nonnull Ref refUsages) { - for (ChangeSignatureUsageProcessor processor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) { - if (processor instanceof ChangeSignatureUsageProcessorEx && ((ChangeSignatureUsageProcessorEx) processor).setupDefaultValues - (myChangeInfo, refUsages, myProject)) { - return false; - } - } - MultiMap conflictDescriptions = new MultiMap<>(); - for (ChangeSignatureUsageProcessor usageProcessor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) { - final MultiMap conflicts = usageProcessor.findConflicts(myChangeInfo, refUsages); - for (PsiElement key : conflicts.keySet()) { - Collection collection = conflictDescriptions.get(key); - if (collection.size() == 0) { - collection = new HashSet<>(); + final UsageInfo[] usagesIn = refUsages.get(); + RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions); + Set usagesSet = new HashSet<>(Arrays.asList(usagesIn)); + RenameUtil.removeConflictUsages(usagesSet); + if (!conflictDescriptions.isEmpty()) { + if (myProject.getApplication().isUnitTestMode()) { + throw new ConflictsInTestsException(conflictDescriptions.values()); + } + if (myPrepareSuccessfulSwingThreadCallback != null) { + ConflictsDialog dialog = prepareConflictsDialog(conflictDescriptions, usagesIn); + dialog.show(); + if (!dialog.isOK()) { + if (dialog.isShowConflicts()) { + prepareSuccessful(); + } + return false; + } + } } - collection.addAll(conflicts.get(key)); - conflictDescriptions.put(key, collection); - } - } - final UsageInfo[] usagesIn = refUsages.get(); - RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions); - Set usagesSet = new HashSet<>(Arrays.asList(usagesIn)); - RenameUtil.removeConflictUsages(usagesSet); - if (!conflictDescriptions.isEmpty()) { - if (myProject.getApplication().isUnitTestMode()) { - throw new ConflictsInTestsException(conflictDescriptions.values()); - } - if (myPrepareSuccessfulSwingThreadCallback != null) { - ConflictsDialog dialog = prepareConflictsDialog(conflictDescriptions, usagesIn); - dialog.show(); - if (!dialog.isOK()) { - if (dialog.isShowConflicts()) { - prepareSuccessful(); - } - return false; + if (myChangeInfo.isReturnTypeChanged()) { + askToRemoveCovariantOverriders(usagesSet); } - } - } - if (myChangeInfo.isReturnTypeChanged()) { - askToRemoveCovariantOverriders(usagesSet); + refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()])); + prepareSuccessful(); + return true; } - refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()])); - prepareSuccessful(); - return true; - } - - @RequiredUIAccess - private void askToRemoveCovariantOverriders(Set usages) { - if (PsiUtil.isLanguageLevel5OrHigher(myChangeInfo.getMethod())) { - List covariantOverriderInfos = new ArrayList<>(); - for (UsageInfo usageInfo : usages) { - if (usageInfo instanceof OverriderUsageInfo) { - final OverriderUsageInfo info = (OverriderUsageInfo) usageInfo; - PsiMethod overrider = info.getElement(); - PsiMethod baseMethod = info.getBaseMethod(); - PsiSubstitutor substitutor = calculateSubstitutor(overrider, baseMethod); - PsiType type; - try { - type = substitutor.substitute(getChangeInfo().newReturnType.getType(myChangeInfo.getMethod(), myManager)); - } catch (IncorrectOperationException e) { - LOG.error(e); - return; - } - final PsiType overriderType = overrider.getReturnType(); - if (overriderType != null && type.isAssignableFrom(overriderType)) { - covariantOverriderInfos.add(usageInfo); - } - } - } + @RequiredUIAccess + private void askToRemoveCovariantOverriders(Set usages) { + if (PsiUtil.isLanguageLevel5OrHigher(myChangeInfo.getMethod())) { + List covariantOverriderInfos = new ArrayList<>(); + for (UsageInfo usageInfo : usages) { + if (usageInfo instanceof OverriderUsageInfo) { + final OverriderUsageInfo info = (OverriderUsageInfo)usageInfo; + PsiMethod overrider = info.getElement(); + PsiMethod baseMethod = info.getBaseMethod(); + PsiSubstitutor substitutor = calculateSubstitutor(overrider, baseMethod); + PsiType type; + try { + type = substitutor.substitute(getChangeInfo().newReturnType.getType(myChangeInfo.getMethod(), myManager)); + } + catch (IncorrectOperationException e) { + LOG.error(e); + return; + } + final PsiType overriderType = overrider.getReturnType(); + if (overriderType != null && type.isAssignableFrom(overriderType)) { + covariantOverriderInfos.add(usageInfo); + } + } + } - // to be able to do filtering - preprocessCovariantOverriders(covariantOverriderInfos); + // to be able to do filtering + preprocessCovariantOverriders(covariantOverriderInfos); - if (!covariantOverriderInfos.isEmpty()) { - if (myProject.getApplication().isUnitTestMode() || !isProcessCovariantOverriders()) { - for (UsageInfo usageInfo : covariantOverriderInfos) { - usages.remove(usageInfo); - } + if (!covariantOverriderInfos.isEmpty()) { + if (myProject.getApplication().isUnitTestMode() || !isProcessCovariantOverriders()) { + for (UsageInfo usageInfo : covariantOverriderInfos) { + usages.remove(usageInfo); + } + } + } } - } } - } - protected void preprocessCovariantOverriders(final List covariantOverriderInfos) { - } + protected void preprocessCovariantOverriders(final List covariantOverriderInfos) { + } - @RequiredUIAccess - protected boolean isProcessCovariantOverriders() { - return Messages.showYesNoDialog( - myProject, - RefactoringLocalize.doYouWantToProcessOverridingMethodsWithCovariantReturnType().get(), - JavaChangeSignatureHandler.REFACTORING_NAME.get(), - UIUtil.getQuestionIcon() - ) == DialogWrapper.OK_EXIT_CODE; - } + @RequiredUIAccess + protected boolean isProcessCovariantOverriders() { + return Messages.showYesNoDialog( + myProject, + RefactoringLocalize.doYouWantToProcessOverridingMethodsWithCovariantReturnType().get(), + JavaChangeSignatureHandler.REFACTORING_NAME.get(), + UIUtil.getQuestionIcon() + ) == DialogWrapper.OK_EXIT_CODE; + } - public static void makeEmptyBody(final PsiElementFactory factory, final PsiMethod delegate) throws IncorrectOperationException { - PsiCodeBlock body = delegate.getBody(); - if (body != null) { - body.replace(factory.createCodeBlock()); - } else { - delegate.add(factory.createCodeBlock()); + public static void makeEmptyBody(final PsiElementFactory factory, final PsiMethod delegate) throws IncorrectOperationException { + PsiCodeBlock body = delegate.getBody(); + if (body != null) { + body.replace(factory.createCodeBlock()); + } + else { + delegate.add(factory.createCodeBlock()); + } + PsiUtil.setModifierProperty(delegate, PsiModifier.ABSTRACT, false); } - PsiUtil.setModifierProperty(delegate, PsiModifier.ABSTRACT, false); - } - @Nullable - public static PsiCallExpression addDelegatingCallTemplate(final PsiMethod delegate, final String newName) throws IncorrectOperationException { - Project project = delegate.getProject(); - PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); - PsiCodeBlock body = delegate.getBody(); - assert body != null; - final PsiCallExpression callExpression; - if (delegate.isConstructor()) { - PsiElement callStatement = factory.createStatementFromText("this();", null); - callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); - callStatement = body.add(callStatement); - callExpression = (PsiCallExpression) ((PsiExpressionStatement) callStatement).getExpression(); - } else { - if (PsiType.VOID.equals(delegate.getReturnType())) { - PsiElement callStatement = factory.createStatementFromText(newName + "();", null); - callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); - callStatement = body.add(callStatement); - callExpression = (PsiCallExpression) ((PsiExpressionStatement) callStatement).getExpression(); - } else { - PsiElement callStatement = factory.createStatementFromText("return " + newName + "();", null); - callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); - callStatement = body.add(callStatement); - callExpression = (PsiCallExpression) ((PsiReturnStatement) callStatement).getReturnValue(); - } + @Nullable + public static PsiCallExpression addDelegatingCallTemplate( + final PsiMethod delegate, + final String newName + ) throws IncorrectOperationException { + Project project = delegate.getProject(); + PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); + PsiCodeBlock body = delegate.getBody(); + assert body != null; + final PsiCallExpression callExpression; + if (delegate.isConstructor()) { + PsiElement callStatement = factory.createStatementFromText("this();", null); + callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); + callStatement = body.add(callStatement); + callExpression = (PsiCallExpression)((PsiExpressionStatement)callStatement).getExpression(); + } + else { + if (PsiType.VOID.equals(delegate.getReturnType())) { + PsiElement callStatement = factory.createStatementFromText(newName + "();", null); + callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); + callStatement = body.add(callStatement); + callExpression = (PsiCallExpression)((PsiExpressionStatement)callStatement).getExpression(); + } + else { + PsiElement callStatement = factory.createStatementFromText("return " + newName + "();", null); + callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); + callStatement = body.add(callStatement); + callExpression = (PsiCallExpression)((PsiReturnStatement)callStatement).getReturnValue(); + } + } + return callExpression; } - return callExpression; - } - public static PsiSubstitutor calculateSubstitutor(PsiMethod derivedMethod, PsiMethod baseMethod) { - PsiSubstitutor substitutor; - if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) { - substitutor = PsiSubstitutor.EMPTY; - } else { - final PsiClass baseClass = baseMethod.getContainingClass(); - final PsiClass derivedClass = derivedMethod.getContainingClass(); - if (baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) { - final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, derivedClass, - PsiSubstitutor.EMPTY); - final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor); - final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); - final PsiSubstitutor superMethodSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, - superMethodSignature); - substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor; - } else { - substitutor = PsiSubstitutor.EMPTY; - } + public static PsiSubstitutor calculateSubstitutor(PsiMethod derivedMethod, PsiMethod baseMethod) { + PsiSubstitutor substitutor; + if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) { + substitutor = PsiSubstitutor.EMPTY; + } + else { + final PsiClass baseClass = baseMethod.getContainingClass(); + final PsiClass derivedClass = derivedMethod.getContainingClass(); + if (baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) { + final PsiSubstitutor superClassSubstitutor = + TypeConversionUtil.getSuperClassSubstitutor(baseClass, derivedClass, PsiSubstitutor.EMPTY); + final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor); + final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); + final PsiSubstitutor superMethodSubstitutor = + MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature); + substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor; + } + else { + substitutor = PsiSubstitutor.EMPTY; + } + } + return substitutor; } - return substitutor; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureUtil.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureUtil.java index bc740ffeb..e2818df42 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureUtil.java @@ -26,6 +26,7 @@ import consulo.language.psi.PsiElement; import consulo.language.util.IncorrectOperationException; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.util.lang.Comparing; import java.util.ArrayList; @@ -35,88 +36,99 @@ * @author dsl */ public class ChangeSignatureUtil { - private ChangeSignatureUtil() { - } - - public static void synchronizeList(Parent list, - final List newElements, - ChildrenGenerator generator, - final boolean[] shouldRemoveChild) throws IncorrectOperationException { + private ChangeSignatureUtil() { + } - ArrayList elementsToRemove = null; - List elements; + public static void synchronizeList( + Parent list, + final List newElements, + ChildrenGenerator generator, + final boolean[] shouldRemoveChild + ) throws IncorrectOperationException { + ArrayList elementsToRemove = null; + List elements; - int index = 0; - while (true) { - elements = generator.getChildren(list); - if (index == newElements.size()) { - break; - } + int index = 0; + while (true) { + elements = generator.getChildren(list); + if (index == newElements.size()) { + break; + } - if (elementsToRemove == null) { - elementsToRemove = new ArrayList(); - for (int i = 0; i < shouldRemoveChild.length; i++) { - if (shouldRemoveChild[i] && i < elements.size()) { - elementsToRemove.add(elements.get(i)); - } - } - } + if (elementsToRemove == null) { + elementsToRemove = new ArrayList<>(); + for (int i = 0; i < shouldRemoveChild.length; i++) { + if (shouldRemoveChild[i] && i < elements.size()) { + elementsToRemove.add(elements.get(i)); + } + } + } - Child oldElement = index < elements.size() ? elements.get(index) : null; - Child newElement = newElements.get(index); - if (newElement != null) { - if (!newElement.equals(oldElement)) { - if (oldElement != null && elementsToRemove.contains(oldElement)) { - oldElement.delete(); - index--; - } else { - assert list.isWritable() : PsiUtilBase.getVirtualFile(list); - list.addBefore(newElement, oldElement); - if (list.equals(newElement.getParent())) { - newElement.delete(); + Child oldElement = index < elements.size() ? elements.get(index) : null; + Child newElement = newElements.get(index); + if (newElement != null) { + if (!newElement.equals(oldElement)) { + if (oldElement != null && elementsToRemove.contains(oldElement)) { + oldElement.delete(); + index--; + } + else { + assert list.isWritable() : PsiUtilBase.getVirtualFile(list); + list.addBefore(newElement, oldElement); + if (list.equals(newElement.getParent())) { + newElement.delete(); + } + } + } + } + else if (newElements.size() > 1 && (!elements.isEmpty() || index < newElements.size() - 1)) { + PsiElement anchor; + if (index == 0) { + anchor = list.getFirstChild(); + } + else { + anchor = index - 1 < elements.size() ? elements.get(index - 1) : null; + } + final PsiElement psi = Factory.createSingleLeafElement( + JavaTokenType.COMMA, + ",", + 0, + 1, + SharedImplUtil.findCharTableByTree(list.getNode()), + list.getManager() + ).getPsi(); + if (anchor != null) { + list.addAfter(psi, anchor); + } + else { + list.add(psi); + } } - } + index++; } - } else { - if (newElements.size() > 1 && (!elements.isEmpty() || index < newElements.size() - 1)) { - PsiElement anchor; - if (index == 0) { - anchor = list.getFirstChild(); - } else { - anchor = index - 1 < elements.size() ? elements.get(index - 1) : null; - } - final PsiElement psi = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, SharedImplUtil.findCharTableByTree(list.getNode()), list.getManager()).getPsi(); - if (anchor != null) { - list.addAfter(psi, anchor); - } else { - list.add(psi); - } + for (int i = newElements.size(); i < elements.size(); i++) { + Child element = elements.get(i); + element.delete(); } - } - index++; } - for (int i = newElements.size(); i < elements.size(); i++) { - Child element = elements.get(i); - element.delete(); - } - } - - public static void invokeChangeSignatureOn(PsiMethod method, Project project) { - final ChangeSignatureHandler handler = RefactoringSupportProvider.forLanguage(method.getLanguage()).getChangeSignatureHandler(); - handler.invoke(project, new PsiElement[]{method}, null); - } - public static boolean deepTypeEqual(PsiType type1, PsiType type2) { - if (type1 == type2) { - return true; + @RequiredUIAccess + public static void invokeChangeSignatureOn(PsiMethod method, Project project) { + final ChangeSignatureHandler handler = RefactoringSupportProvider.forLanguage(method.getLanguage()).getChangeSignatureHandler(); + handler.invoke(project, new PsiElement[]{method}, null); } - if (type1 == null || !type1.equals(type2)) { - return false; + + public static boolean deepTypeEqual(PsiType type1, PsiType type2) { + if (type1 == type2) { + return true; + } + if (type1 == null || !type1.equals(type2)) { + return false; + } + return Comparing.equal(type1.getCanonicalText(true), type2.getCanonicalText(true)); } - return Comparing.equal(type1.getCanonicalText(true), type2.getCanonicalText(true)); - } - public interface ChildrenGenerator { - List getChildren(Parent parent); - } + public interface ChildrenGenerator { + List getChildren(Parent parent); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java index ba1ada650..5169e19ae 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java @@ -35,8 +35,10 @@ import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.psi.util.TypeConversionUtil; import com.intellij.java.language.util.VisibilityUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.annotation.component.ExtensionImpl; -import consulo.application.ApplicationManager; +import consulo.application.Application; import consulo.ide.impl.idea.refactoring.changeSignature.DefaultValueChooser; import consulo.java.impl.refactoring.changeSignature.ChangeSignatureUsageProcessorEx; import consulo.java.language.module.util.JavaClassNames; @@ -57,14 +59,13 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.MoveRenameUsageInfo; import consulo.usage.UsageInfo; import consulo.util.collection.ContainerUtil; import consulo.util.collection.MultiMap; -import consulo.util.lang.Pair; import consulo.util.lang.StringUtil; -import consulo.util.lang.function.Condition; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -75,953 +76,1091 @@ */ @ExtensionImpl(id = "javaProcessor") public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessorEx { - private static final Logger LOG = Logger.getInstance(JavaChangeSignatureUsageProcessor.class); + private static final Logger LOG = Logger.getInstance(JavaChangeSignatureUsageProcessor.class); - private static boolean isJavaUsage(UsageInfo info) { - final PsiElement element = info.getElement(); - if (element == null) { - return false; + @RequiredReadAction + private static boolean isJavaUsage(UsageInfo info) { + PsiElement element = info.getElement(); + return element != null && element.getLanguage() == JavaLanguage.INSTANCE; } - return element.getLanguage() == JavaLanguage.INSTANCE; - } - - @Override - public UsageInfo[] findUsages(ChangeInfo info) { - if (info instanceof JavaChangeInfo) { - return new JavaChangeSignatureUsageSearcher((JavaChangeInfo) info).findUsages(); - } else { - return UsageInfo.EMPTY_ARRAY; - } - } - - @Override - public MultiMap findConflicts(ChangeInfo info, Ref refUsages) { - if (info instanceof JavaChangeInfo) { - return new ConflictSearcher((JavaChangeInfo) info).findConflicts(refUsages); - } else { - return new MultiMap(); - } - } - @Override - public boolean processUsage(ChangeInfo changeInfo, UsageInfo usage, boolean beforeMethodChange, UsageInfo[] usages) { - if (!isJavaUsage(usage)) { - return false; - } - if (!(changeInfo instanceof JavaChangeInfo)) { - return false; + @Nonnull + @Override + public UsageInfo[] findUsages(@Nonnull ChangeInfo info) { + if (info instanceof JavaChangeInfo javaChangeInfo) { + return new JavaChangeSignatureUsageSearcher(javaChangeInfo).findUsages(); + } + else { + return UsageInfo.EMPTY_ARRAY; + } } - - if (beforeMethodChange) { - if (usage instanceof CallerUsageInfo) { - final CallerUsageInfo callerUsageInfo = (CallerUsageInfo) usage; - processCallerMethod((JavaChangeInfo) changeInfo, callerUsageInfo.getMethod(), null, callerUsageInfo.isToInsertParameter(), callerUsageInfo.isToInsertException()); - return true; - } else if (usage instanceof OverriderUsageInfo) { - OverriderUsageInfo info = (OverriderUsageInfo) usage; - final PsiMethod method = info.getElement(); - final PsiMethod baseMethod = info.getBaseMethod(); - if (info.isOriginalOverrider()) { - processPrimaryMethod((JavaChangeInfo) changeInfo, method, baseMethod, false); - } else { - processCallerMethod((JavaChangeInfo) changeInfo, method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions()); + @Nonnull + @Override + @RequiredReadAction + public MultiMap findConflicts(@Nonnull ChangeInfo info, SimpleReference refUsages) { + if (info instanceof JavaChangeInfo javaChangeInfo) { + return new ConflictSearcher(javaChangeInfo).findConflicts(refUsages); } - return true; - } - - } else { - PsiElement element = usage.getElement(); - LOG.assertTrue(element != null); - - if (usage instanceof DefaultConstructorImplicitUsageInfo) { - final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo) usage; - PsiMethod constructor = defConstructorUsage.getConstructor(); - if (!constructor.isPhysical()) { - final boolean toPropagate = changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl) changeInfo).propagateParametersMethods.remove(constructor); - final PsiClass containingClass = defConstructorUsage.getContainingClass(); - constructor = (PsiMethod) containingClass.add(constructor); - PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(containingClass.getModifierList()), true); - if (toPropagate) { - ((JavaChangeInfoImpl) changeInfo).propagateParametersMethods.add(constructor); - } + else { + return new MultiMap<>(); } - addSuperCall((JavaChangeInfo) changeInfo, constructor, defConstructorUsage.getBaseConstructor(), usages); - return true; - } else if (usage instanceof NoConstructorClassUsageInfo) { - addDefaultConstructor(((JavaChangeInfo) changeInfo), ((NoConstructorClassUsageInfo) usage).getPsiClass(), usages); - return true; - } else if (usage instanceof MethodCallUsageInfo) { - final MethodCallUsageInfo methodCallInfo = (MethodCallUsageInfo) usage; - processMethodUsage(methodCallInfo.getElement(), (JavaChangeInfo) changeInfo, methodCallInfo.isToChangeArguments(), methodCallInfo.isToCatchExceptions(), methodCallInfo - .getReferencedMethod(), methodCallInfo.getSubstitutor(), usages); - return true; - } else if (usage instanceof ChangeSignatureParameterUsageInfo) { - String newName = ((ChangeSignatureParameterUsageInfo) usage).newParameterName; - String oldName = ((ChangeSignatureParameterUsageInfo) usage).oldParameterName; - processParameterUsage((PsiReferenceExpression) element, oldName, newName); - return true; - } else if (usage instanceof CallReferenceUsageInfo) { - ((CallReferenceUsageInfo) usage).getReference().handleChangeSignature(changeInfo); - return true; - } else if (element instanceof PsiEnumConstant) { - fixActualArgumentsList(((PsiEnumConstant) element).getArgumentList(), (JavaChangeInfo) changeInfo, true, PsiSubstitutor.EMPTY); - return true; - } else if (!(usage instanceof OverriderUsageInfo)) { - PsiReference reference = usage instanceof MoveRenameUsageInfo ? usage.getReference() : element.getReference(); - if (reference != null) { - PsiElement target = changeInfo.getMethod(); - if (target != null) { - reference.bindToElement(target); - } - } - } } - return false; - } - private static void processParameterUsage(PsiReferenceExpression ref, String oldName, String newName) throws IncorrectOperationException { + @Override + @RequiredWriteAction + public boolean processUsage( + @Nonnull ChangeInfo changeInfo, + @Nonnull UsageInfo usage, + boolean beforeMethodChange, + @Nonnull UsageInfo[] usages + ) { + if (!isJavaUsage(usage)) { + return false; + } + if (!(changeInfo instanceof JavaChangeInfo javaChangeInfo)) { + return false; + } - PsiElement last = ref.getReferenceNameElement(); - if (last instanceof PsiIdentifier && last.getText().equals(oldName)) { - PsiElementFactory factory = JavaPsiFacade.getInstance(ref.getProject()).getElementFactory(); - PsiIdentifier newNameIdentifier = factory.createIdentifier(newName); - last.replace(newNameIdentifier); + if (beforeMethodChange) { + if (usage instanceof CallerUsageInfo callerUsageInfo) { + processCallerMethod( + javaChangeInfo, + callerUsageInfo.getMethod(), + null, + callerUsageInfo.isToInsertParameter(), + callerUsageInfo.isToInsertException() + ); + return true; + } + else if (usage instanceof OverriderUsageInfo info) { + PsiMethod method = info.getElement(); + PsiMethod baseMethod = info.getBaseMethod(); + if (info.isOriginalOverrider()) { + processPrimaryMethod(javaChangeInfo, method, baseMethod, false); + } + else { + processCallerMethod(javaChangeInfo, method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions()); + } + return true; + } + } + else { + PsiElement element = usage.getElement(); + LOG.assertTrue(element != null); + + if (usage instanceof DefaultConstructorImplicitUsageInfo defConstructorUsage) { + PsiMethod constructor = defConstructorUsage.getConstructor(); + if (!constructor.isPhysical()) { + boolean toPropagate = javaChangeInfo instanceof JavaChangeInfoImpl changeInfoImpl + && changeInfoImpl.propagateParametersMethods.remove(constructor); + PsiClass containingClass = defConstructorUsage.getContainingClass(); + constructor = (PsiMethod)containingClass.add(constructor); + PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(containingClass.getModifierList()), true); + if (toPropagate) { + ((JavaChangeInfoImpl)javaChangeInfo).propagateParametersMethods.add(constructor); + } + } + addSuperCall(javaChangeInfo, constructor, defConstructorUsage.getBaseConstructor(), usages); + return true; + } + else if (usage instanceof NoConstructorClassUsageInfo noConstructorClassUsageInfo) { + addDefaultConstructor(javaChangeInfo, noConstructorClassUsageInfo.getPsiClass(), usages); + return true; + } + else if (usage instanceof MethodCallUsageInfo methodCallInfo) { + processMethodUsage( + methodCallInfo.getElement(), + javaChangeInfo, + methodCallInfo.isToChangeArguments(), + methodCallInfo.isToCatchExceptions(), + methodCallInfo.getReferencedMethod(), + methodCallInfo.getSubstitutor(), + usages + ); + return true; + } + else if (usage instanceof ChangeSignatureParameterUsageInfo parameterUsageInfo) { + String newName = parameterUsageInfo.newParameterName; + String oldName = parameterUsageInfo.oldParameterName; + processParameterUsage((PsiReferenceExpression)element, oldName, newName); + return true; + } + else if (usage instanceof CallReferenceUsageInfo callUsageInfo) { + callUsageInfo.getReference().handleChangeSignature(javaChangeInfo); + return true; + } + else if (element instanceof PsiEnumConstant enumConstant) { + fixActualArgumentsList( + enumConstant.getArgumentList(), + javaChangeInfo, + true, + PsiSubstitutor.EMPTY + ); + return true; + } + else if (!(usage instanceof OverriderUsageInfo)) { + PsiReference reference = usage instanceof MoveRenameUsageInfo ? usage.getReference() : element.getReference(); + if (reference != null) { + PsiElement target = javaChangeInfo.getMethod(); + if (target != null) { + reference.bindToElement(target); + } + } + } + } + return false; } - } - - - private static void addDefaultConstructor(JavaChangeInfo changeInfo, PsiClass aClass, final UsageInfo[] usages) throws IncorrectOperationException { - if (!(aClass instanceof PsiAnonymousClass)) { - PsiElementFactory factory = JavaPsiFacade.getElementFactory(aClass.getProject()); - PsiMethod defaultConstructor = factory.createMethodFromText(aClass.getName() + "(){}", aClass); - defaultConstructor = (PsiMethod) CodeStyleManager.getInstance(aClass.getProject()).reformat(defaultConstructor); - defaultConstructor = (PsiMethod) aClass.add(defaultConstructor); - PsiUtil.setModifierProperty(defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true); - addSuperCall(changeInfo, defaultConstructor, null, usages); - } else { - final PsiElement parent = aClass.getParent(); - if (parent instanceof PsiNewExpression) { - final PsiExpressionList argumentList = ((PsiNewExpression) parent).getArgumentList(); - final PsiClass baseClass = changeInfo.getMethod().getContainingClass(); - final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY); - fixActualArgumentsList(argumentList, changeInfo, true, substitutor); - } + + private static void processParameterUsage( + PsiReferenceExpression ref, + String oldName, + String newName + ) throws IncorrectOperationException { + PsiElement last = ref.getReferenceNameElement(); + if (last instanceof PsiIdentifier identifier && identifier.getText().equals(oldName)) { + PsiElementFactory factory = JavaPsiFacade.getInstance(ref.getProject()).getElementFactory(); + PsiIdentifier newNameIdentifier = factory.createIdentifier(newName); + last.replace(newNameIdentifier); + } } - } - - private static void addSuperCall(JavaChangeInfo changeInfo, PsiMethod constructor, PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(constructor.getProject()); - PsiExpressionStatement superCall = (PsiExpressionStatement) factory.createStatementFromText("super();", constructor); - PsiCodeBlock body = constructor.getBody(); - assert body != null; - PsiStatement[] statements = body.getStatements(); - if (statements.length > 0) { - superCall = (PsiExpressionStatement) body.addBefore(superCall, statements[0]); - } else { - superCall = (PsiExpressionStatement) body.add(superCall); + + @RequiredReadAction + private static void addDefaultConstructor( + JavaChangeInfo changeInfo, + PsiClass aClass, + UsageInfo[] usages + ) throws IncorrectOperationException { + if (!(aClass instanceof PsiAnonymousClass)) { + PsiElementFactory factory = JavaPsiFacade.getElementFactory(aClass.getProject()); + PsiMethod defaultConstructor = factory.createMethodFromText(aClass.getName() + "(){}", aClass); + defaultConstructor = (PsiMethod)CodeStyleManager.getInstance(aClass.getProject()).reformat(defaultConstructor); + defaultConstructor = (PsiMethod)aClass.add(defaultConstructor); + PsiUtil.setModifierProperty(defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true); + addSuperCall(changeInfo, defaultConstructor, null, usages); + } + else if (aClass.getParent() instanceof PsiNewExpression newExpr) { + PsiClass baseClass = changeInfo.getMethod().getContainingClass(); + PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY); + fixActualArgumentsList(newExpr.getArgumentList(), changeInfo, true, substitutor); + } } - PsiMethodCallExpression callExpression = (PsiMethodCallExpression) superCall.getExpression(); - final PsiClass aClass = constructor.getContainingClass(); - final PsiClass baseClass = changeInfo.getMethod().getContainingClass(); - final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY); - processMethodUsage(callExpression.getMethodExpression(), changeInfo, true, false, callee, substitutor, usages); - } - - private static void processMethodUsage(PsiElement ref, - JavaChangeInfo changeInfo, - boolean toChangeArguments, - boolean toCatchExceptions, - PsiMethod callee, - PsiSubstitutor subsitutor, - final UsageInfo[] usages) throws IncorrectOperationException { - if (changeInfo.isNameChanged()) { - if (ref instanceof PsiJavaCodeReferenceElement) { - PsiElement last = ((PsiJavaCodeReferenceElement) ref).getReferenceNameElement(); - if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.getOldName())) { - last.replace(changeInfo.getNewNameIdentifier()); + + @RequiredReadAction + private static void addSuperCall( + JavaChangeInfo changeInfo, + PsiMethod constructor, + PsiMethod callee, + UsageInfo[] usages + ) throws IncorrectOperationException { + PsiElementFactory factory = JavaPsiFacade.getElementFactory(constructor.getProject()); + PsiExpressionStatement superCall = (PsiExpressionStatement)factory.createStatementFromText("super();", constructor); + PsiCodeBlock body = constructor.getBody(); + assert body != null; + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0) { + superCall = (PsiExpressionStatement)body.addBefore(superCall, statements[0]); } - } + else { + superCall = (PsiExpressionStatement)body.add(superCall); + } + PsiMethodCallExpression callExpression = (PsiMethodCallExpression)superCall.getExpression(); + PsiClass aClass = constructor.getContainingClass(); + PsiClass baseClass = changeInfo.getMethod().getContainingClass(); + PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY); + processMethodUsage(callExpression.getMethodExpression(), changeInfo, true, false, callee, substitutor, usages); } - final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref); - if (toChangeArguments) { - final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref); - LOG.assertTrue(list != null); - boolean toInsertDefaultValue = needDefaultValue(changeInfo, caller); - if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) { - final PsiExpression qualifierExpression = ((PsiReferenceExpression) ref).getQualifierExpression(); - if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) { - toInsertDefaultValue = false; + @RequiredReadAction + private static void processMethodUsage( + PsiElement ref, + JavaChangeInfo changeInfo, + boolean toChangeArguments, + boolean toCatchExceptions, + PsiMethod callee, + PsiSubstitutor subsitutor, + UsageInfo[] usages + ) throws IncorrectOperationException { + if (changeInfo.isNameChanged() + && ref instanceof PsiJavaCodeReferenceElement javaCodeRef + && javaCodeRef.getReferenceNameElement() instanceof PsiIdentifier identifier + && identifier.getText().equals(changeInfo.getOldName())) { + identifier.replace(changeInfo.getNewNameIdentifier()); + } + + PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref); + if (toChangeArguments) { + PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref); + LOG.assertTrue(list != null); + boolean toInsertDefaultValue = needDefaultValue(changeInfo, caller); + if (toInsertDefaultValue && ref instanceof PsiReferenceExpression refExpr) { + PsiExpression qualifierExpression = refExpr.getQualifierExpression(); + if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) { + toInsertDefaultValue = false; + } + } + + fixActualArgumentsList(list, changeInfo, toInsertDefaultValue, subsitutor); } - } - fixActualArgumentsList(list, changeInfo, toInsertDefaultValue, subsitutor); + if (toCatchExceptions) { + if (!(ref instanceof PsiReferenceExpression + && JavaHighlightUtil.isSuperOrThisCall(PsiTreeUtil.getParentOfType(ref, PsiStatement.class), true, false))) { + if (needToCatchExceptions(changeInfo, caller)) { + PsiClassType[] newExceptions = + callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo); + fixExceptions(ref, newExceptions); + } + } + } } - if (toCatchExceptions) { - if (!(ref instanceof PsiReferenceExpression && JavaHighlightUtil.isSuperOrThisCall(PsiTreeUtil.getParentOfType(ref, PsiStatement.class), true, false))) { - if (needToCatchExceptions(changeInfo, caller)) { - PsiClassType[] newExceptions = callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo); - fixExceptions(ref, newExceptions); + private static boolean callerSignatureIsAboutToChangeToo(PsiMethod caller, UsageInfo[] usages) { + for (UsageInfo usage : usages) { + if (usage instanceof MethodCallUsageInfo callUsageInfo + && MethodSignatureUtil.isSuperMethod(callUsageInfo.getReferencedMethod(), caller)) { + return true; + } } - } + return false; } - } - private static boolean callerSignatureIsAboutToChangeToo(final PsiMethod caller, final UsageInfo[] usages) { - for (UsageInfo usage : usages) { - if (usage instanceof MethodCallUsageInfo && MethodSignatureUtil.isSuperMethod(((MethodCallUsageInfo) usage).getReferencedMethod(), caller)) { - return true; - } + private static PsiClassType[] getCalleeChangedExceptionInfo(PsiMethod callee) { + return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified! } - return false; - } - - private static PsiClassType[] getCalleeChangedExceptionInfo(final PsiMethod callee) { - return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified! - } - - private static void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException { - //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions - newExceptions = filterCheckedExceptions(newExceptions); - - PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class); - if (context instanceof PsiTryStatement) { - PsiTryStatement tryStatement = (PsiTryStatement) context; - PsiCodeBlock tryBlock = tryStatement.getTryBlock(); - - //Remove unused catches - Collection classes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock); - PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters(); - for (PsiParameter parameter : catchParameters) { - final PsiType caughtType = parameter.getType(); - - if (!(caughtType instanceof PsiClassType)) { - continue; + + private static void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException { + //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions + newExceptions = filterCheckedExceptions(newExceptions); + + if (PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class) instanceof PsiTryStatement tryStmt) { + PsiCodeBlock tryBlock = tryStmt.getTryBlock(); + + //Remove unused catches + Collection classes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock); + PsiParameter[] catchParameters = tryStmt.getCatchBlockParameters(); + for (PsiParameter parameter : catchParameters) { + PsiType caughtType = parameter.getType(); + + if (!(caughtType instanceof PsiClassType)) { + continue; + } + if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)caughtType)) { + continue; + } + + if (!isCatchParameterRedundant((PsiClassType)caughtType, classes)) { + continue; + } + parameter.getParent().delete(); //delete catch section + } + + PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock); + addExceptions(exceptionsToAdd, tryStmt); + + adjustPossibleEmptyTryStatement(tryStmt); } - if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType) caughtType)) { - continue; + else { + newExceptions = filterUnhandledExceptions(newExceptions, ref); + if (newExceptions.length > 0) { + //Add new try statement + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(ref.getProject()); + PsiTryStatement tryStatement = + (PsiTryStatement)elementFactory.createStatementFromText("try {} catch (Exception e) {}", null); + PsiStatement anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class); + LOG.assertTrue(anchor != null); + tryStatement.getTryBlock().add(anchor); + tryStatement = (PsiTryStatement)anchor.getParent().addAfter(tryStatement, anchor); + + addExceptions(newExceptions, tryStatement); + anchor.delete(); + tryStatement.getCatchSections()[0].delete(); //Delete dummy catch section + } } + } - if (!isCatchParameterRedundant((PsiClassType) caughtType, classes)) { - continue; + private static PsiClassType[] filterCheckedExceptions(PsiClassType[] exceptions) { + List result = new ArrayList(); + for (PsiClassType exceptionType : exceptions) { + if (!ExceptionUtil.isUncheckedException(exceptionType)) { + result.add(exceptionType); + } } - parameter.getParent().delete(); //delete catch section - } - - PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock); - addExceptions(exceptionsToAdd, tryStatement); - - adjustPossibleEmptyTryStatement(tryStatement); - } else { - newExceptions = filterUnhandledExceptions(newExceptions, ref); - if (newExceptions.length > 0) { - //Add new try statement - PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(ref.getProject()); - PsiTryStatement tryStatement = (PsiTryStatement) elementFactory.createStatementFromText("try {} catch (Exception e) {}", null); - PsiStatement anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class); - LOG.assertTrue(anchor != null); - tryStatement.getTryBlock().add(anchor); - tryStatement = (PsiTryStatement) anchor.getParent().addAfter(tryStatement, anchor); - - addExceptions(newExceptions, tryStatement); - anchor.delete(); - tryStatement.getCatchSections()[0].delete(); //Delete dummy catch section - } - } - } - - private static PsiClassType[] filterCheckedExceptions(PsiClassType[] exceptions) { - List result = new ArrayList(); - for (PsiClassType exceptionType : exceptions) { - if (!ExceptionUtil.isUncheckedException(exceptionType)) { - result.add(exceptionType); - } + return result.toArray(new PsiClassType[result.size()]); } - return result.toArray(new PsiClassType[result.size()]); - } - - private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement) throws IncorrectOperationException { - PsiCodeBlock tryBlock = tryStatement.getTryBlock(); - if (tryBlock != null) { - if (tryStatement.getCatchSections().length == 0 && tryStatement.getFinallyBlock() == null) { - PsiElement firstBodyElement = tryBlock.getFirstBodyElement(); - if (firstBodyElement != null) { - tryStatement.getParent().addRangeAfter(firstBodyElement, tryBlock.getLastBodyElement(), tryStatement); + + private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement) throws IncorrectOperationException { + PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if (tryBlock != null) { + if (tryStatement.getCatchSections().length == 0 && tryStatement.getFinallyBlock() == null) { + PsiElement firstBodyElement = tryBlock.getFirstBodyElement(); + if (firstBodyElement != null) { + tryStatement.getParent().addRangeAfter(firstBodyElement, tryBlock.getLastBodyElement(), tryStatement); + } + tryStatement.delete(); + } } - tryStatement.delete(); - } } - } - private static void addExceptions(PsiClassType[] exceptionsToAdd, PsiTryStatement tryStatement) throws IncorrectOperationException { - for (PsiClassType type : exceptionsToAdd) { - final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject()); - String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type).names[0]; - name = styleManager.suggestUniqueVariableName(name, tryStatement, false); + private static void addExceptions(PsiClassType[] exceptionsToAdd, PsiTryStatement tryStatement) throws IncorrectOperationException { + for (PsiClassType type : exceptionsToAdd) { + JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject()); + String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type).names[0]; + name = styleManager.suggestUniqueVariableName(name, tryStatement, false); - PsiCatchSection catchSection = JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory().createCatchSection(type, name, tryStatement); - tryStatement.add(catchSection); - } - } - - private static PsiClassType[] filterUnhandledExceptions(PsiClassType[] exceptions, PsiElement place) { - List result = new ArrayList(); - for (PsiClassType exception : exceptions) { - if (!ExceptionUtil.isHandled(exception, place)) { - result.add(exception); - } + PsiCatchSection catchSection = + JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory().createCatchSection(type, name, tryStatement); + tryStatement.add(catchSection); + } } - return result.toArray(new PsiClassType[result.size()]); - } - private static boolean isCatchParameterRedundant(PsiClassType catchParamType, Collection thrownTypes) { - for (PsiType exceptionType : thrownTypes) { - if (exceptionType.isConvertibleFrom(catchParamType)) { - return false; - } - } - return true; - } - - //This methods works equally well for primary usages as well as for propagated callers' usages - private static void fixActualArgumentsList(PsiExpressionList list, JavaChangeInfo changeInfo, boolean toInsertDefaultValue, PsiSubstitutor substitutor) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); - if (changeInfo.isParameterSetOrOrderChanged()) { - if (changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl) changeInfo).isPropagationEnabled) { - final ParameterInfoImpl[] createdParmsInfo = ((JavaChangeInfoImpl) changeInfo).getCreatedParmsInfoWithoutVarargs(); - for (ParameterInfoImpl info : createdParmsInfo) { - PsiExpression newArg; - if (toInsertDefaultValue) { - newArg = createDefaultValue(changeInfo, factory, info, list); - } else { - newArg = factory.createExpressionFromText(info.getName(), list); - } - if (newArg != null) { - JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list.add(newArg)); - } - } - } else { - final PsiExpression[] args = list.getExpressions(); - final int nonVarargCount = getNonVarargCount(changeInfo, args); - final int varargCount = args.length - nonVarargCount; - if (varargCount < 0) { - return; - } - PsiExpression[] newVarargInitializers = null; - - final int newArgsLength; - final int newNonVarargCount; - final JavaParameterInfo[] newParms = changeInfo.getNewParameters(); - if (changeInfo.isArrayToVarargs()) { - newNonVarargCount = newParms.length - 1; - final JavaParameterInfo lastNewParm = newParms[newParms.length - 1]; - final PsiExpression arrayToConvert = args[lastNewParm.getOldIndex()]; - if (arrayToConvert instanceof PsiNewExpression) { - final PsiNewExpression expression = (PsiNewExpression) arrayToConvert; - final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer(); - if (arrayInitializer != null) { - newVarargInitializers = arrayInitializer.getInitializers(); + private static PsiClassType[] filterUnhandledExceptions(PsiClassType[] exceptions, PsiElement place) { + List result = new ArrayList<>(); + for (PsiClassType exception : exceptions) { + if (!ExceptionUtil.isHandled(exception, place)) { + result.add(exception); } - } - newArgsLength = newVarargInitializers == null ? newParms.length : newNonVarargCount + newVarargInitializers.length; - } else if (changeInfo.isRetainsVarargs()) { - newNonVarargCount = newParms.length - 1; - newArgsLength = newNonVarargCount + varargCount; - } else if (changeInfo.isObtainsVarags()) { - newNonVarargCount = newParms.length - 1; - newArgsLength = newNonVarargCount; - } else { - newNonVarargCount = newParms.length; - newArgsLength = newParms.length; } + return result.toArray(new PsiClassType[result.size()]); + } - String[] oldVarargs = null; - if (changeInfo.wasVararg() && !changeInfo.isRetainsVarargs()) { - oldVarargs = new String[varargCount]; - for (int i = nonVarargCount; i < args.length; i++) { - oldVarargs[i - nonVarargCount] = args[i].getText(); - } + private static boolean isCatchParameterRedundant(PsiClassType catchParamType, Collection thrownTypes) { + for (PsiType exceptionType : thrownTypes) { + if (exceptionType.isConvertibleFrom(catchParamType)) { + return false; + } } + return true; + } - final PsiExpression[] newArgs = new PsiExpression[newArgsLength]; - for (int i = 0; i < newNonVarargCount; i++) { - if (newParms[i].getOldIndex() == nonVarargCount && oldVarargs != null) { - PsiType type = newParms[i].createType(changeInfo.getMethod(), list.getManager()); - if (type instanceof PsiArrayType) { - type = substitutor.substitute(type); - type = TypeConversionUtil.erasure(type); - String typeText = type.getCanonicalText(); - if (type instanceof PsiEllipsisType) { - typeText = typeText.replace("...", "[]"); - } - String text = "new " + typeText + "{" + StringUtil.join(oldVarargs, ",") + "}"; - newArgs[i] = factory.createExpressionFromText(text, changeInfo.getMethod()); - continue; + //This methods works equally well for primary usages as well as for propagated callers' usages + @RequiredUIAccess + private static void fixActualArgumentsList( + PsiExpressionList list, + JavaChangeInfo changeInfo, + boolean toInsertDefaultValue, + PsiSubstitutor substitutor + ) throws IncorrectOperationException { + PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); + if (changeInfo.isParameterSetOrOrderChanged()) { + if (changeInfo instanceof JavaChangeInfoImpl changeInfoImpl && changeInfoImpl.isPropagationEnabled) { + ParameterInfoImpl[] createdParmsInfo = changeInfoImpl.getCreatedParmsInfoWithoutVarargs(); + for (ParameterInfoImpl info : createdParmsInfo) { + PsiExpression newArg; + if (toInsertDefaultValue) { + newArg = createDefaultValue(changeInfoImpl, factory, info, list); + } + else { + newArg = factory.createExpressionFromText(info.getName(), list); + } + if (newArg != null) { + JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list.add(newArg)); + } + } } - } - newArgs[i] = createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args); - } - if (changeInfo.isArrayToVarargs()) { - if (newVarargInitializers == null) { - newArgs[newNonVarargCount] = createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args); - } else { - System.arraycopy(newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length); - } - } else { - final int newVarargCount = newArgsLength - newNonVarargCount; - LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount); - for (int i = newNonVarargCount; i < newArgsLength; i++) { - final int oldIndex = newParms[newNonVarargCount].getOldIndex(); - if (oldIndex >= 0 && oldIndex != nonVarargCount) { - newArgs[i] = createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args); - } else { - System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount); - break; + else { + PsiExpression[] args = list.getExpressions(); + int nonVarargCount = getNonVarargCount(changeInfo, args); + int varargCount = args.length - nonVarargCount; + if (varargCount < 0) { + return; + } + PsiExpression[] newVarargInitializers = null; + + int newArgsLength; + int newNonVarargCount; + JavaParameterInfo[] newParms = changeInfo.getNewParameters(); + if (changeInfo.isArrayToVarargs()) { + newNonVarargCount = newParms.length - 1; + JavaParameterInfo lastNewParm = newParms[newParms.length - 1]; + PsiExpression arrayToConvert = args[lastNewParm.getOldIndex()]; + if (arrayToConvert instanceof PsiNewExpression newExpr) { + PsiArrayInitializerExpression arrayInitializer = newExpr.getArrayInitializer(); + if (arrayInitializer != null) { + newVarargInitializers = arrayInitializer.getInitializers(); + } + } + newArgsLength = newVarargInitializers == null ? newParms.length : newNonVarargCount + newVarargInitializers.length; + } + else if (changeInfo.isRetainsVarargs()) { + newNonVarargCount = newParms.length - 1; + newArgsLength = newNonVarargCount + varargCount; + } + else if (changeInfo.isObtainsVarags()) { + newNonVarargCount = newParms.length - 1; + newArgsLength = newNonVarargCount; + } + else { + newNonVarargCount = newParms.length; + newArgsLength = newParms.length; + } + + String[] oldVarargs = null; + if (changeInfo.wasVararg() && !changeInfo.isRetainsVarargs()) { + oldVarargs = new String[varargCount]; + for (int i = nonVarargCount; i < args.length; i++) { + oldVarargs[i - nonVarargCount] = args[i].getText(); + } + } + + PsiExpression[] newArgs = new PsiExpression[newArgsLength]; + for (int i = 0; i < newNonVarargCount; i++) { + if (newParms[i].getOldIndex() == nonVarargCount && oldVarargs != null) { + PsiType type = newParms[i].createType(changeInfo.getMethod(), list.getManager()); + if (type instanceof PsiArrayType) { + type = substitutor.substitute(type); + type = TypeConversionUtil.erasure(type); + String typeText = type.getCanonicalText(); + if (type instanceof PsiEllipsisType) { + typeText = typeText.replace("...", "[]"); + } + String text = "new " + typeText + "{" + StringUtil.join(oldVarargs, ",") + "}"; + newArgs[i] = factory.createExpressionFromText(text, changeInfo.getMethod()); + continue; + } + } + newArgs[i] = createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args); + } + if (changeInfo.isArrayToVarargs()) { + if (newVarargInitializers == null) { + newArgs[newNonVarargCount] = + createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args); + } + else { + System.arraycopy(newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length); + } + } + else { + int newVarargCount = newArgsLength - newNonVarargCount; + LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount); + for (int i = newNonVarargCount; i < newArgsLength; i++) { + int oldIndex = newParms[newNonVarargCount].getOldIndex(); + if (oldIndex >= 0 && oldIndex != nonVarargCount) { + newArgs[i] = createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args); + } + else { + System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount); + break; + } + } + } + ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm()); } - } } - ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm()); - } } - } - private static int getNonVarargCount(JavaChangeInfo changeInfo, PsiExpression[] args) { - if (!changeInfo.wasVararg()) { - return args.length; - } - return changeInfo.getOldParameterTypes().length - 1; - } - - - @Nullable - private static PsiExpression createActualArgument(JavaChangeInfo changeInfo, - final PsiExpressionList list, - final JavaParameterInfo info, - final boolean toInsertDefaultValue, - final PsiExpression[] args) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); - final int index = info.getOldIndex(); - if (index >= 0) { - return args[index]; - } else { - if (toInsertDefaultValue) { - return createDefaultValue(changeInfo, factory, info, list); - } else { - return factory.createExpressionFromText(info.getName(), list); - } - } - } - - @Nullable - private static PsiExpression createDefaultValue(JavaChangeInfo changeInfo, - final PsiElementFactory factory, - final JavaParameterInfo info, - final PsiExpressionList list) throws IncorrectOperationException { - if (info.isUseAnySingleVariable()) { - final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper(); - final PsiType type = info.getTypeWrapper().getType(changeInfo.getMethod(), list.getManager()); - final VariablesProcessor processor = new VariablesProcessor(false) { - @Override - protected boolean check(PsiVariable var, ResolveState state) { - if (var instanceof PsiField && !resolveHelper.isAccessible((PsiField) var, list, null)) { - return false; - } - if (var instanceof PsiLocalVariable && list.getTextRange().getStartOffset() <= var.getTextRange().getStartOffset()) { - return false; - } - if (PsiTreeUtil.isAncestor(var, list, false)) { - return false; - } - final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType()); - return type.isAssignableFrom(varType); + private static int getNonVarargCount(JavaChangeInfo changeInfo, PsiExpression[] args) { + if (!changeInfo.wasVararg()) { + return args.length; } + return changeInfo.getOldParameterTypes().length - 1; + } - @Override - public boolean execute(@Nonnull PsiElement pe, ResolveState state) { - super.execute(pe, state); - return size() < 2; + + @Nullable + @RequiredReadAction + private static PsiExpression createActualArgument( + JavaChangeInfo changeInfo, + PsiExpressionList list, + JavaParameterInfo info, + boolean toInsertDefaultValue, + PsiExpression[] args + ) throws IncorrectOperationException { + PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); + int index = info.getOldIndex(); + if (index >= 0) { + return args[index]; } - }; - PsiScopesUtil.treeWalkUp(processor, list, null); - if (processor.size() == 1) { - final PsiVariable result = processor.getResult(0); - return factory.createExpressionFromText(result.getName(), list); - } - if (processor.size() == 0) { - final PsiClass parentClass = PsiTreeUtil.getParentOfType(list, PsiClass.class); - if (parentClass != null) { - PsiClass containingClass = parentClass; - final Set containingClasses = new HashSet(); - while (containingClass != null) { - if (type.isAssignableFrom(factory.createType(containingClass, PsiSubstitutor.EMPTY))) { - containingClasses.add(containingClass); - } - containingClass = PsiTreeUtil.getParentOfType(containingClass, PsiClass.class); - } - if (containingClasses.size() == 1) { - return RefactoringChangeUtil.createThisExpression(parentClass.getManager(), containingClasses.contains(parentClass) ? null : containingClasses.iterator().next()); - } + else if (toInsertDefaultValue) { + return createDefaultValue(changeInfo, factory, info, list); + } + else { + return factory.createExpressionFromText(info.getName(), list); } - } } - final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class); - final String defaultValue = info.getDefaultValue(); - return callExpression != null ? info.getValue(callExpression) : defaultValue.length() > 0 ? factory.createExpressionFromText(defaultValue, list) : null; - } + @Nullable + @RequiredReadAction + private static PsiExpression createDefaultValue( + JavaChangeInfo changeInfo, + PsiElementFactory factory, + JavaParameterInfo info, + PsiExpressionList list + ) throws IncorrectOperationException { + if (info.isUseAnySingleVariable()) { + PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper(); + PsiType type = info.getTypeWrapper().getType(changeInfo.getMethod(), list.getManager()); + VariablesProcessor processor = new VariablesProcessor(false) { + @Override + @RequiredReadAction + protected boolean check(PsiVariable var, ResolveState state) { + if (var instanceof PsiField field && !resolveHelper.isAccessible(field, list, null)) { + return false; + } + if (var instanceof PsiLocalVariable && list.getTextRange().getStartOffset() <= var.getTextRange().getStartOffset()) { + return false; + } + if (PsiTreeUtil.isAncestor(var, list, false)) { + return false; + } + PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType()); + return type.isAssignableFrom(varType); + } - @Override - public boolean processPrimaryMethod(ChangeInfo changeInfo) { - if (!JavaLanguage.INSTANCE.equals(changeInfo.getLanguage()) || !(changeInfo instanceof JavaChangeInfo)) { - return false; + @Override + public boolean execute(@Nonnull PsiElement pe, ResolveState state) { + super.execute(pe, state); + return size() < 2; + } + }; + PsiScopesUtil.treeWalkUp(processor, list, null); + if (processor.size() == 1) { + PsiVariable result = processor.getResult(0); + return factory.createExpressionFromText(result.getName(), list); + } + if (processor.size() == 0) { + PsiClass parentClass = PsiTreeUtil.getParentOfType(list, PsiClass.class); + if (parentClass != null) { + PsiClass containingClass = parentClass; + Set containingClasses = new HashSet<>(); + while (containingClass != null) { + if (type.isAssignableFrom(factory.createType(containingClass, PsiSubstitutor.EMPTY))) { + containingClasses.add(containingClass); + } + containingClass = PsiTreeUtil.getParentOfType(containingClass, PsiClass.class); + } + if (containingClasses.size() == 1) { + return RefactoringChangeUtil.createThisExpression( + parentClass.getManager(), + containingClasses.contains(parentClass) ? null : containingClasses.iterator().next() + ); + } + } + } + } + PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class); + String defaultValue = info.getDefaultValue(); + return callExpression != null + ? info.getValue(callExpression) + : defaultValue.length() > 0 + ? factory.createExpressionFromText(defaultValue, list) + : null; } - final PsiElement element = changeInfo.getMethod(); - LOG.assertTrue(element instanceof PsiMethod); - if (changeInfo.isGenerateDelegate()) { - generateDelegate((JavaChangeInfo) changeInfo); + + + @Override + @RequiredWriteAction + public boolean processPrimaryMethod(ChangeInfo changeInfo) { + if (!JavaLanguage.INSTANCE.equals(changeInfo.getLanguage()) || !(changeInfo instanceof JavaChangeInfo)) { + return false; + } + PsiElement element = changeInfo.getMethod(); + LOG.assertTrue(element instanceof PsiMethod); + if (changeInfo.isGenerateDelegate()) { + generateDelegate((JavaChangeInfo)changeInfo); + } + processPrimaryMethod((JavaChangeInfo)changeInfo, (PsiMethod)element, null, true); + return true; } - processPrimaryMethod((JavaChangeInfo) changeInfo, (PsiMethod) element, null, true); - return true; - } - - @Override - public boolean shouldPreviewUsages(ChangeInfo changeInfo, UsageInfo[] usages) { - return false; - } - - @Override - public boolean setupDefaultValues(ChangeInfo changeInfo, Ref refUsages, Project project) { - if (!(changeInfo instanceof JavaChangeInfo)) { - return false; + + @Override + public boolean shouldPreviewUsages(@Nonnull ChangeInfo changeInfo, @Nonnull UsageInfo[] usages) { + return false; } - for (UsageInfo usageInfo : refUsages.get()) { - if (usageInfo instanceof MethodCallUsageInfo) { - MethodCallUsageInfo methodCallUsageInfo = (MethodCallUsageInfo) usageInfo; - if (methodCallUsageInfo.isToChangeArguments()) { - final PsiElement element = methodCallUsageInfo.getElement(); - if (element == null) { - continue; - } - final PsiMethod caller = RefactoringUtil.getEnclosingMethod(element); - final boolean needDefaultValue = needDefaultValue(changeInfo, caller); - if (needDefaultValue && (caller == null || !MethodSignatureUtil.isSuperMethod(methodCallUsageInfo.getReferencedMethod(), caller))) { - final ParameterInfo[] parameters = changeInfo.getNewParameters(); - for (ParameterInfo parameter : parameters) { - final String defaultValue = parameter.getDefaultValue(); - if (defaultValue == null && parameter.getOldIndex() == -1) { - ((ParameterInfoImpl) parameter).setDefaultValue(""); - if (!ApplicationManager.getApplication().isUnitTestMode()) { - final PsiType type = ((ParameterInfoImpl) parameter).getTypeWrapper().getType(element, element.getManager()); - final DefaultValueChooser chooser = new DefaultValueChooser(project, parameter.getName(), PsiTypesUtil.getDefaultValueOfType(type)); - chooser.show(); - if (chooser.isOK()) { - if (chooser.feelLucky()) { - parameter.setUseAnySingleVariable(true); - } else { - ((ParameterInfoImpl) parameter).setDefaultValue(chooser.getDefaultValue()); + + @Override + @RequiredUIAccess + public boolean setupDefaultValues(ChangeInfo changeInfo, SimpleReference refUsages, Project project) { + if (!(changeInfo instanceof JavaChangeInfo)) { + return false; + } + for (UsageInfo usageInfo : refUsages.get()) { + if (usageInfo instanceof MethodCallUsageInfo methodCallUsageInfo && methodCallUsageInfo.isToChangeArguments()) { + PsiElement element = methodCallUsageInfo.getElement(); + if (element == null) { + continue; + } + PsiMethod caller = RefactoringUtil.getEnclosingMethod(element); + boolean needDefaultValue = needDefaultValue(changeInfo, caller); + if (needDefaultValue + && (caller == null || !MethodSignatureUtil.isSuperMethod(methodCallUsageInfo.getReferencedMethod(), caller))) { + ParameterInfo[] parameters = changeInfo.getNewParameters(); + for (ParameterInfo parameter : parameters) { + String defaultValue = parameter.getDefaultValue(); + if (defaultValue == null && parameter.getOldIndex() == -1) { + ((ParameterInfoImpl)parameter).setDefaultValue(""); + if (!Application.get().isUnitTestMode()) { + PsiType type = ((ParameterInfoImpl)parameter).getTypeWrapper().getType(element, element.getManager()); + DefaultValueChooser chooser = + new DefaultValueChooser(project, parameter.getName(), PsiTypesUtil.getDefaultValueOfType(type)); + chooser.show(); + if (chooser.isOK()) { + if (chooser.feelLucky()) { + parameter.setUseAnySingleVariable(true); + } + else { + ((ParameterInfoImpl)parameter).setDefaultValue(chooser.getDefaultValue()); + } + } + else { + return true; + } + } + } } - } else { - return true; - } } - } } - } } - } + return false; } - return false; - } - - @Override - public void registerConflictResolvers(List snapshots, @Nonnull ResolveSnapshotProvider resolveSnapshotProvider, UsageInfo[] usages, ChangeInfo changeInfo) { - snapshots.add(resolveSnapshotProvider.createSnapshot(changeInfo.getMethod())); - for (UsageInfo usage : usages) { - if (usage instanceof OverriderUsageInfo) { - snapshots.add(resolveSnapshotProvider.createSnapshot(usage.getElement())); - } + + @Override + public void registerConflictResolvers( + List snapshots, + @Nonnull ResolveSnapshotProvider resolveSnapshotProvider, + UsageInfo[] usages, + ChangeInfo changeInfo + ) { + snapshots.add(resolveSnapshotProvider.createSnapshot(changeInfo.getMethod())); + for (UsageInfo usage : usages) { + if (usage instanceof OverriderUsageInfo) { + snapshots.add(resolveSnapshotProvider.createSnapshot(usage.getElement())); + } + } } - } - - private static boolean needDefaultValue(ChangeInfo changeInfo, PsiMethod method) { - return !(changeInfo instanceof JavaChangeInfoImpl) || !((JavaChangeInfoImpl) changeInfo).propagateParametersMethods.contains(method); - } - - public static void generateDelegate(JavaChangeInfo changeInfo) throws IncorrectOperationException { - final PsiMethod delegate = generateDelegatePrototype(changeInfo); - PsiClass targetClass = changeInfo.getMethod().getContainingClass(); - LOG.assertTrue(targetClass != null); - targetClass.addBefore(delegate, changeInfo.getMethod()); - } - - public static PsiMethod generateDelegatePrototype(JavaChangeInfo changeInfo) { - final PsiMethod delegate = (PsiMethod) changeInfo.getMethod().copy(); - PsiClass targetClass = changeInfo.getMethod().getContainingClass(); - LOG.assertTrue(targetClass != null); - if (targetClass.isInterface() && delegate.getBody() == null) { - delegate.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true); + + private static boolean needDefaultValue(ChangeInfo changeInfo, PsiMethod method) { + return !(changeInfo instanceof JavaChangeInfoImpl changeInfoImpl && changeInfoImpl.propagateParametersMethods.contains(method)); } - PsiElementFactory factory = JavaPsiFacade.getElementFactory(targetClass.getProject()); - ChangeSignatureProcessor.makeEmptyBody(factory, delegate); - final PsiCallExpression callExpression = ChangeSignatureProcessor.addDelegatingCallTemplate(delegate, changeInfo.getNewName()); - addDelegateArguments(changeInfo, factory, callExpression); - return delegate; - } - - private static void addDelegateArguments(JavaChangeInfo changeInfo, PsiElementFactory factory, final PsiCallExpression callExpression) throws IncorrectOperationException { - final JavaParameterInfo[] newParms = changeInfo.getNewParameters(); - final String[] oldParameterNames = changeInfo.getOldParameterNames(); - for (int i = 0; i < newParms.length; i++) { - JavaParameterInfo newParm = newParms[i]; - final PsiExpression actualArg; - if (newParm.getOldIndex() >= 0) { - actualArg = factory.createExpressionFromText(oldParameterNames[newParm.getOldIndex()], callExpression); - } else { - actualArg = changeInfo.getValue(i, callExpression); - } - final PsiExpressionList argumentList = callExpression.getArgumentList(); - if (actualArg != null && argumentList != null) { - JavaCodeStyleManager.getInstance(callExpression.getProject()).shortenClassReferences(argumentList.add(actualArg)); - } + + public static void generateDelegate(JavaChangeInfo changeInfo) throws IncorrectOperationException { + PsiMethod delegate = generateDelegatePrototype(changeInfo); + PsiClass targetClass = changeInfo.getMethod().getContainingClass(); + LOG.assertTrue(targetClass != null); + targetClass.addBefore(delegate, changeInfo.getMethod()); } - } - private static void processPrimaryMethod(JavaChangeInfo changeInfo, PsiMethod method, PsiMethod baseMethod, boolean isOriginal) throws IncorrectOperationException { - PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); + public static PsiMethod generateDelegatePrototype(JavaChangeInfo changeInfo) { + PsiMethod delegate = (PsiMethod)changeInfo.getMethod().copy(); + PsiClass targetClass = changeInfo.getMethod().getContainingClass(); + LOG.assertTrue(targetClass != null); + if (targetClass.isInterface() && delegate.getBody() == null) { + delegate.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true); + } + PsiElementFactory factory = JavaPsiFacade.getElementFactory(targetClass.getProject()); + ChangeSignatureProcessor.makeEmptyBody(factory, delegate); + PsiCallExpression callExpression = ChangeSignatureProcessor.addDelegatingCallTemplate(delegate, changeInfo.getNewName()); + addDelegateArguments(changeInfo, factory, callExpression); + return delegate; + } - if (changeInfo.isVisibilityChanged()) { - PsiModifierList modifierList = method.getModifierList(); - final String highestVisibility = isOriginal ? changeInfo.getNewVisibility() : VisibilityUtil.getHighestVisibility(changeInfo.getNewVisibility(), VisibilityUtil.getVisibilityModifier - (modifierList)); - VisibilityUtil.setVisibility(modifierList, highestVisibility); + private static void addDelegateArguments( + JavaChangeInfo changeInfo, + PsiElementFactory factory, + PsiCallExpression callExpression + ) throws IncorrectOperationException { + JavaParameterInfo[] newParms = changeInfo.getNewParameters(); + String[] oldParameterNames = changeInfo.getOldParameterNames(); + for (int i = 0; i < newParms.length; i++) { + JavaParameterInfo newParm = newParms[i]; + PsiExpression actualArg; + if (newParm.getOldIndex() >= 0) { + actualArg = factory.createExpressionFromText(oldParameterNames[newParm.getOldIndex()], callExpression); + } + else { + actualArg = changeInfo.getValue(i, callExpression); + } + PsiExpressionList argumentList = callExpression.getArgumentList(); + if (actualArg != null && argumentList != null) { + JavaCodeStyleManager.getInstance(callExpression.getProject()).shortenClassReferences(argumentList.add(actualArg)); + } + } } - if (changeInfo.isNameChanged()) { - String newName = baseMethod == null ? changeInfo.getNewName() : RefactoringUtil.suggestNewOverriderName(method.getName(), baseMethod.getName(), changeInfo.getNewName()); + @RequiredWriteAction + private static void processPrimaryMethod( + JavaChangeInfo changeInfo, + PsiMethod method, + PsiMethod baseMethod, + boolean isOriginal + ) throws IncorrectOperationException { + PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); + + if (changeInfo.isVisibilityChanged()) { + PsiModifierList modifierList = method.getModifierList(); + String highestVisibility = isOriginal + ? changeInfo.getNewVisibility() + : VisibilityUtil.getHighestVisibility(changeInfo.getNewVisibility(), VisibilityUtil.getVisibilityModifier(modifierList)); + VisibilityUtil.setVisibility(modifierList, highestVisibility); + } - if (newName != null && !newName.equals(method.getName())) { - final PsiIdentifier nameId = method.getNameIdentifier(); - assert nameId != null; - nameId.replace(JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createIdentifier(newName)); - } - } + if (changeInfo.isNameChanged()) { + String newName = baseMethod == null + ? changeInfo.getNewName() + : RefactoringUtil.suggestNewOverriderName(method.getName(), baseMethod.getName(), changeInfo.getNewName()); - final PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(method, baseMethod); + if (newName != null && !newName.equals(method.getName())) { + PsiIdentifier nameId = method.getNameIdentifier(); + assert nameId != null; + nameId.replace(JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createIdentifier(newName)); + } + } - if (changeInfo.isReturnTypeChanged()) { - PsiType newTypeElement = changeInfo.getNewReturnType().getType(changeInfo.getMethod().getParameterList(), method.getManager()); - final PsiType returnType = substitutor.substitute(newTypeElement); - // don't modify return type for non-Java overriders (EJB) - if (method.getName().equals(changeInfo.getNewName())) { - final PsiTypeElement typeElement = method.getReturnTypeElement(); - if (typeElement != null) { - typeElement.replace(factory.createTypeElement(returnType)); + PsiSubstitutor substitutor = + baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(method, baseMethod); + + if (changeInfo.isReturnTypeChanged()) { + PsiType newTypeElement = changeInfo.getNewReturnType().getType(changeInfo.getMethod().getParameterList(), method.getManager()); + PsiType returnType = substitutor.substitute(newTypeElement); + // don't modify return type for non-Java overriders (EJB) + if (method.getName().equals(changeInfo.getNewName())) { + PsiTypeElement typeElement = method.getReturnTypeElement(); + if (typeElement != null) { + typeElement.replace(factory.createTypeElement(returnType)); + } + } } - } - } - PsiParameterList list = method.getParameterList(); - PsiParameter[] parameters = list.getParameters(); - - final JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters(); - final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount() : 0; - PsiParameter[] newParms = new PsiParameter[Math.max(parameterInfos.length - delta, 0)]; - final String[] oldParameterNames = changeInfo.getOldParameterNames(); - final String[] oldParameterTypes = changeInfo.getOldParameterTypes(); - for (int i = 0; i < newParms.length; i++) { - JavaParameterInfo info = parameterInfos[i]; - int index = info.getOldIndex(); - if (index >= 0) { - PsiParameter parameter = parameters[index]; - newParms[i] = parameter; - - String oldName = oldParameterNames[index]; - if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) { - PsiIdentifier newIdentifier = factory.createIdentifier(info.getName()); - parameter.getNameIdentifier().replace(newIdentifier); + PsiParameterList list = method.getParameterList(); + PsiParameter[] parameters = list.getParameters(); + + JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters(); + int delta = + baseMethod != null ? baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount() : 0; + PsiParameter[] newParms = new PsiParameter[Math.max(parameterInfos.length - delta, 0)]; + String[] oldParameterNames = changeInfo.getOldParameterNames(); + String[] oldParameterTypes = changeInfo.getOldParameterTypes(); + for (int i = 0; i < newParms.length; i++) { + JavaParameterInfo info = parameterInfos[i]; + int index = info.getOldIndex(); + if (index >= 0) { + PsiParameter parameter = parameters[index]; + newParms[i] = parameter; + + String oldName = oldParameterNames[index]; + if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) { + PsiIdentifier newIdentifier = factory.createIdentifier(info.getName()); + parameter.getNameIdentifier().replace(newIdentifier); + } + + String oldType = oldParameterTypes[index]; + if (!oldType.equals(info.getTypeText())) { + parameter.normalizeDeclaration(); + PsiType newType = + substitutor.substitute(info.createType(changeInfo.getMethod().getParameterList(), method.getManager())); + + parameter.getTypeElement().replace(factory.createTypeElement(newType)); + } + } + else { + newParms[i] = createNewParameter(changeInfo, info, substitutor); + } } - String oldType = oldParameterTypes[index]; - if (!oldType.equals(info.getTypeText())) { - parameter.normalizeDeclaration(); - PsiType newType = substitutor.substitute(info.createType(changeInfo.getMethod().getParameterList(), method.getManager())); + resolveParameterVsFieldsConflicts(newParms, method, list, changeInfo.toRemoveParm()); + fixJavadocsForChangedMethod(method, changeInfo, newParms.length); + if (changeInfo.isExceptionSetOrOrderChanged()) { + PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo); + fixPrimaryThrowsLists(method, newExceptions); + } + } - parameter.getTypeElement().replace(factory.createTypeElement(newType)); + private static PsiClassType[] getPrimaryChangedExceptionInfo(JavaChangeInfo changeInfo) throws IncorrectOperationException { + ThrownExceptionInfo[] newExceptionInfos = changeInfo.getNewExceptions(); + PsiClassType[] newExceptions = new PsiClassType[newExceptionInfos.length]; + PsiMethod method = changeInfo.getMethod(); + for (int i = 0; i < newExceptions.length; i++) { + newExceptions[i] = + (PsiClassType)newExceptionInfos[i].createType(method, method.getManager()); //context really does not matter here } - } else { - newParms[i] = createNewParameter(changeInfo, info, substitutor); - } + return newExceptions; } + private static void processCallerMethod( + JavaChangeInfo changeInfo, + PsiMethod caller, + PsiMethod baseMethod, + boolean toInsertParams, + boolean toInsertThrows + ) throws IncorrectOperationException { + LOG.assertTrue(toInsertParams || toInsertThrows); + if (toInsertParams) { + List newParameters = new ArrayList<>(); + ContainerUtil.addAll(newParameters, caller.getParameterList().getParameters()); + JavaParameterInfo[] primaryNewParms = changeInfo.getNewParameters(); + PsiSubstitutor substitutor = + baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(caller, baseMethod); + PsiClass aClass = changeInfo.getMethod().getContainingClass(); + PsiClass callerContainingClass = caller.getContainingClass(); + PsiSubstitutor psiSubstitutor = aClass != null && callerContainingClass != null && callerContainingClass.isInheritor( + aClass, + true + ) ? TypeConversionUtil.getSuperClassSubstitutor + (aClass, callerContainingClass, substitutor) : PsiSubstitutor.EMPTY; + for (JavaParameterInfo info : primaryNewParms) { + if (info.getOldIndex() < 0) { + newParameters.add(createNewParameter(changeInfo, info, psiSubstitutor, substitutor)); + } + } + PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]); + boolean[] toRemoveParm = new boolean[arrayed.length]; + Arrays.fill(toRemoveParm, false); + resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm); + } - resolveParameterVsFieldsConflicts(newParms, method, list, changeInfo.toRemoveParm()); - fixJavadocsForChangedMethod(method, changeInfo, newParms.length); - if (changeInfo.isExceptionSetOrOrderChanged()) { - final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo); - fixPrimaryThrowsLists(method, newExceptions); - } - } - - private static PsiClassType[] getPrimaryChangedExceptionInfo(JavaChangeInfo changeInfo) throws IncorrectOperationException { - final ThrownExceptionInfo[] newExceptionInfos = changeInfo.getNewExceptions(); - PsiClassType[] newExceptions = new PsiClassType[newExceptionInfos.length]; - final PsiMethod method = changeInfo.getMethod(); - for (int i = 0; i < newExceptions.length; i++) { - newExceptions[i] = (PsiClassType) newExceptionInfos[i].createType(method, method.getManager()); //context really does not matter here - } - return newExceptions; - } - - - private static void processCallerMethod(JavaChangeInfo changeInfo, PsiMethod caller, PsiMethod baseMethod, boolean toInsertParams, boolean toInsertThrows) throws IncorrectOperationException { - LOG.assertTrue(toInsertParams || toInsertThrows); - if (toInsertParams) { - List newParameters = new ArrayList(); - ContainerUtil.addAll(newParameters, caller.getParameterList().getParameters()); - final JavaParameterInfo[] primaryNewParms = changeInfo.getNewParameters(); - PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(caller, baseMethod); - final PsiClass aClass = changeInfo.getMethod().getContainingClass(); - final PsiClass callerContainingClass = caller.getContainingClass(); - final PsiSubstitutor psiSubstitutor = aClass != null && callerContainingClass != null && callerContainingClass.isInheritor(aClass, true) ? TypeConversionUtil.getSuperClassSubstitutor - (aClass, callerContainingClass, substitutor) : PsiSubstitutor.EMPTY; - for (JavaParameterInfo info : primaryNewParms) { - if (info.getOldIndex() < 0) { - newParameters.add(createNewParameter(changeInfo, info, psiSubstitutor, substitutor)); + if (toInsertThrows) { + List newThrowns = new ArrayList<>(); + PsiReferenceList throwsList = caller.getThrowsList(); + ContainerUtil.addAll(newThrowns, throwsList.getReferenceElements()); + ThrownExceptionInfo[] primaryNewExns = changeInfo.getNewExceptions(); + for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) { + if (thrownExceptionInfo.getOldIndex() < 0) { + PsiClassType type = (PsiClassType)thrownExceptionInfo.createType(caller, caller.getManager()); + PsiJavaCodeReferenceElement ref = + JavaPsiFacade.getInstance(caller.getProject()).getElementFactory().createReferenceElementByType(type); + newThrowns.add(ref); + } + } + PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]); + boolean[] toRemoveParm = new boolean[arrayed.length]; + Arrays.fill(toRemoveParm, false); + ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm); } - } - PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]); - boolean[] toRemoveParm = new boolean[arrayed.length]; - Arrays.fill(toRemoveParm, false); - resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm); } - if (toInsertThrows) { - List newThrowns = new ArrayList(); - final PsiReferenceList throwsList = caller.getThrowsList(); - ContainerUtil.addAll(newThrowns, throwsList.getReferenceElements()); - final ThrownExceptionInfo[] primaryNewExns = changeInfo.getNewExceptions(); - for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) { - if (thrownExceptionInfo.getOldIndex() < 0) { - final PsiClassType type = (PsiClassType) thrownExceptionInfo.createType(caller, caller.getManager()); - final PsiJavaCodeReferenceElement ref = JavaPsiFacade.getInstance(caller.getProject()).getElementFactory().createReferenceElementByType(type); - newThrowns.add(ref); + @RequiredReadAction + private static void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException { + PsiElementFactory elementFactory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); + PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length]; + for (int i = 0; i < refs.length; i++) { + refs[i] = elementFactory.createReferenceElementByType(newExceptions[i]); } - } - PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]); - boolean[] toRemoveParm = new boolean[arrayed.length]; - Arrays.fill(toRemoveParm, false); - ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm); - } - } + PsiReferenceList throwsList = elementFactory.createReferenceList(refs); - private static void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException { - PsiElementFactory elementFactory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); - PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length]; - for (int i = 0; i < refs.length; i++) { - refs[i] = elementFactory.createReferenceElementByType(newExceptions[i]); + PsiReferenceList methodThrowsList = (PsiReferenceList)method.getThrowsList().replace(throwsList); + methodThrowsList = (PsiReferenceList)JavaCodeStyleManager.getInstance(method.getProject()).shortenClassReferences(methodThrowsList); + CodeStyleManager.getInstance(method.getManager().getProject()) + .reformatRange(method, method.getParameterList().getTextRange().getEndOffset(), methodThrowsList.getTextRange().getEndOffset()); } - PsiReferenceList throwsList = elementFactory.createReferenceList(refs); - - PsiReferenceList methodThrowsList = (PsiReferenceList) method.getThrowsList().replace(throwsList); - methodThrowsList = (PsiReferenceList) JavaCodeStyleManager.getInstance(method.getProject()).shortenClassReferences(methodThrowsList); - CodeStyleManager.getInstance(method.getManager().getProject()).reformatRange(method, method.getParameterList().getTextRange().getEndOffset(), methodThrowsList.getTextRange().getEndOffset()); - } - - private static void fixJavadocsForChangedMethod(final PsiMethod method, final JavaChangeInfo changeInfo, int newParamsLength) throws IncorrectOperationException { - final PsiParameter[] parameters = method.getParameterList().getParameters(); - final JavaParameterInfo[] newParms = changeInfo.getNewParameters(); - LOG.assertTrue(parameters.length <= newParamsLength); - final Set newParameters = new HashSet(); - final String[] oldParameterNames = changeInfo.getOldParameterNames(); - for (int i = 0; i < newParamsLength; i++) { - JavaParameterInfo newParm = newParms[i]; - if (newParm.getOldIndex() < 0 || newParm.getOldIndex() == i && !(newParm.getName().equals(oldParameterNames[newParm.getOldIndex()]) && newParm.getTypeText().equals(changeInfo - .getOldParameterTypes()[newParm.getOldIndex()]))) { - newParameters.add(parameters[i]); - } - } - RefactoringUtil.fixJavadocsForParams(method, newParameters, new Condition>() { - @Override - public boolean value(Pair pair) { - final PsiParameter parameter = pair.first; - final String oldParamName = pair.second; - final int idx = Arrays.binarySearch(oldParameterNames, oldParamName); - return idx >= 0 && idx == method.getParameterList().getParameterIndex(parameter) && changeInfo.getNewParameters()[idx].getOldIndex() == idx; - } - }); - } - - private static PsiParameter createNewParameter(JavaChangeInfo changeInfo, JavaParameterInfo newParm, PsiSubstitutor... substitutor) throws IncorrectOperationException { - final PsiParameterList list = changeInfo.getMethod().getParameterList(); - final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); - PsiType type = newParm.createType(list, list.getManager()); - for (PsiSubstitutor psiSubstitutor : substitutor) { - type = psiSubstitutor.substitute(type); - } - return factory.createParameter(newParm.getName(), type); - } - - private static void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms, final PsiMethod method, final PsiParameterList list, boolean[] toRemoveParm) throws - IncorrectOperationException { - List conflictResolvers = new ArrayList(); - for (PsiParameter parameter : newParms) { - conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody())); - } - ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm); - JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list); - for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) { - fieldConflictsResolver.fix(); + + private static void fixJavadocsForChangedMethod( + PsiMethod method, + JavaChangeInfo changeInfo, + int newParamsLength + ) throws IncorrectOperationException { + PsiParameter[] parameters = method.getParameterList().getParameters(); + JavaParameterInfo[] newParms = changeInfo.getNewParameters(); + LOG.assertTrue(parameters.length <= newParamsLength); + Set newParameters = new HashSet<>(); + String[] oldParameterNames = changeInfo.getOldParameterNames(); + for (int i = 0; i < newParamsLength; i++) { + JavaParameterInfo newParm = newParms[i]; + if (newParm.getOldIndex() < 0 + || newParm.getOldIndex() == i && !(newParm.getName().equals(oldParameterNames[newParm.getOldIndex()]) + && newParm.getTypeText().equals(changeInfo.getOldParameterTypes()[newParm.getOldIndex()]))) { + newParameters.add(parameters[i]); + } + } + RefactoringUtil.fixJavadocsForParams( + method, + newParameters, + pair -> { + PsiParameter parameter = pair.first; + String oldParamName = pair.second; + int idx = Arrays.binarySearch(oldParameterNames, oldParamName); + return idx >= 0 && idx == method.getParameterList().getParameterIndex(parameter) + && changeInfo.getNewParameters()[idx].getOldIndex() == idx; + } + ); } - } - private static boolean needToCatchExceptions(JavaChangeInfo changeInfo, PsiMethod caller) { - return changeInfo.isExceptionSetOrOrderChanged() && !(changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl) changeInfo).propagateExceptionsMethods.contains(caller)); - } + private static PsiParameter createNewParameter( + JavaChangeInfo changeInfo, + JavaParameterInfo newParm, + PsiSubstitutor... substitutor + ) throws IncorrectOperationException { + PsiParameterList list = changeInfo.getMethod().getParameterList(); + PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); + PsiType type = newParm.createType(list, list.getManager()); + for (PsiSubstitutor psiSubstitutor : substitutor) { + type = psiSubstitutor.substitute(type); + } + return factory.createParameter(newParm.getName(), type); + } - private static class ParameterList implements ChangeSignatureUtil.ChildrenGenerator { - public static final ParameterList INSTANCE = new ParameterList(); + private static void resolveParameterVsFieldsConflicts( + PsiParameter[] newParms, + PsiMethod method, + PsiParameterList list, + boolean[] toRemoveParm + ) throws + IncorrectOperationException { + List conflictResolvers = new ArrayList<>(); + for (PsiParameter parameter : newParms) { + conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody())); + } + ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm); + JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list); + for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) { + fieldConflictsResolver.fix(); + } + } - @Override - public List getChildren(PsiParameterList psiParameterList) { - return Arrays.asList(psiParameterList.getParameters()); + private static boolean needToCatchExceptions(JavaChangeInfo changeInfo, PsiMethod caller) { + return changeInfo.isExceptionSetOrOrderChanged() + && !(changeInfo instanceof JavaChangeInfoImpl changInfoImpl && changInfoImpl.propagateExceptionsMethods.contains(caller)); } - } - private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator { - public static final ThrowsList INSTANCE = new ThrowsList(); + private static class ParameterList implements ChangeSignatureUtil.ChildrenGenerator { + public static final ParameterList INSTANCE = new ParameterList(); - @Override - public List getChildren(PsiReferenceList throwsList) { - return Arrays.asList(throwsList.getReferenceElements()); + @Override + public List getChildren(PsiParameterList psiParameterList) { + return Arrays.asList(psiParameterList.getParameters()); + } } - } - private static class ConflictSearcher { - private final JavaChangeInfo myChangeInfo; + private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator { + public static final ThrowsList INSTANCE = new ThrowsList(); - private ConflictSearcher(JavaChangeInfo changeInfo) { - this.myChangeInfo = changeInfo; + @Override + public List getChildren(PsiReferenceList throwsList) { + return Arrays.asList(throwsList.getReferenceElements()); + } } - public MultiMap findConflicts(Ref refUsages) { - MultiMap conflictDescriptions = new MultiMap(); - addMethodConflicts(conflictDescriptions); - Set usagesSet = new HashSet(Arrays.asList(refUsages.get())); - RenameUtil.removeConflictUsages(usagesSet); - if (myChangeInfo.isVisibilityChanged()) { - try { - addInaccessibilityDescriptions(usagesSet, conflictDescriptions); - } catch (IncorrectOperationException e) { - LOG.error(e); + private static class ConflictSearcher { + private final JavaChangeInfo myChangeInfo; + + private ConflictSearcher(JavaChangeInfo changeInfo) { + this.myChangeInfo = changeInfo; } - } - - for (UsageInfo usageInfo : usagesSet) { - final PsiElement element = usageInfo.getElement(); - if (usageInfo instanceof OverriderUsageInfo) { - final PsiMethod method = (PsiMethod) element; - final PsiMethod baseMethod = ((OverriderUsageInfo) usageInfo).getBaseMethod(); - final int delta = baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount(); - if (delta > 0) { - final boolean[] toRemove = myChangeInfo.toRemoveParm(); - if (toRemove[toRemove.length - 1]) { //todo check if implicit parameter is not the last one - conflictDescriptions.putValue(baseMethod, "Implicit last parameter should not be deleted"); + + @RequiredReadAction + public MultiMap findConflicts(SimpleReference refUsages) { + MultiMap conflictDescriptions = new MultiMap<>(); + addMethodConflicts(conflictDescriptions); + Set usagesSet = new HashSet<>(Arrays.asList(refUsages.get())); + RenameUtil.removeConflictUsages(usagesSet); + if (myChangeInfo.isVisibilityChanged()) { + try { + addInaccessibilityDescriptions(usagesSet, conflictDescriptions); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - } - } else if (element instanceof PsiMethodReferenceExpression) { - conflictDescriptions.putValue(element, "Changed method is used in method reference"); - } - } - return conflictDescriptions; - } + for (UsageInfo usageInfo : usagesSet) { + PsiElement element = usageInfo.getElement(); + if (usageInfo instanceof OverriderUsageInfo overriderUsageInfo) { + PsiMethod method = (PsiMethod)element; + PsiMethod baseMethod = overriderUsageInfo.getBaseMethod(); + int delta = baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount(); + if (delta > 0) { + boolean[] toRemove = myChangeInfo.toRemoveParm(); + if (toRemove[toRemove.length - 1]) { //todo check if implicit parameter is not the last one + conflictDescriptions.putValue(baseMethod, "Implicit last parameter should not be deleted"); + } + } + } + else if (element instanceof PsiMethodReferenceExpression) { + conflictDescriptions.putValue(element, "Changed method is used in method reference"); + } + } - private boolean needToChangeCalls() { - return myChangeInfo.isNameChanged() || myChangeInfo.isParameterSetOrOrderChanged() || myChangeInfo.isExceptionSetOrOrderChanged(); - } + return conflictDescriptions; + } + private boolean needToChangeCalls() { + return myChangeInfo.isNameChanged() || myChangeInfo.isParameterSetOrOrderChanged() || myChangeInfo.isExceptionSetOrOrderChanged(); + } - private void addInaccessibilityDescriptions(Set usages, MultiMap conflictDescriptions) throws IncorrectOperationException { - PsiMethod method = myChangeInfo.getMethod(); - PsiModifierList modifierList = (PsiModifierList) method.getModifierList().copy(); - VisibilityUtil.setVisibility(modifierList, myChangeInfo.getNewVisibility()); - - for (Iterator iterator = usages.iterator(); iterator.hasNext(); ) { - UsageInfo usageInfo = iterator.next(); - PsiElement element = usageInfo.getElement(); - if (element != null) { - if (element instanceof PsiQualifiedReference) { - PsiClass accessObjectClass = null; - PsiElement qualifier = ((PsiQualifiedReference) element).getQualifier(); - if (qualifier instanceof PsiExpression) { - accessObjectClass = (PsiClass) PsiUtil.getAccessObjectClass((PsiExpression) qualifier).getElement(); - } - if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper().isAccessible(method, modifierList, element, accessObjectClass, null)) { - LocalizeValue message = RefactoringLocalize.zeroWith1VisibilityIsNotAccessibleFrom2( - RefactoringUIUtil.getDescription(method, true), - VisibilityUtil.toPresentableText(myChangeInfo.getNewVisibility()), - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true) - ); - conflictDescriptions.putValue(method, message.get()); - if (!needToChangeCalls()) { - iterator.remove(); - } + private void addInaccessibilityDescriptions( + Set usages, + MultiMap conflictDescriptions + ) throws IncorrectOperationException { + PsiMethod method = myChangeInfo.getMethod(); + PsiModifierList modifierList = (PsiModifierList)method.getModifierList().copy(); + VisibilityUtil.setVisibility(modifierList, myChangeInfo.getNewVisibility()); + + for (Iterator iterator = usages.iterator(); iterator.hasNext(); ) { + UsageInfo usageInfo = iterator.next(); + PsiElement element = usageInfo.getElement(); + if (element != null) { + if (element instanceof PsiQualifiedReference qualifiedRef) { + PsiClass accessObjectClass = qualifiedRef.getQualifier() instanceof PsiExpression expression + ? (PsiClass)PsiUtil.getAccessObjectClass(expression).getElement() + : null; + + if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper() + .isAccessible(method, modifierList, element, accessObjectClass, null)) { + LocalizeValue message = RefactoringLocalize.zeroWith1VisibilityIsNotAccessibleFrom2( + RefactoringUIUtil.getDescription(method, true), + VisibilityUtil.toPresentableText(myChangeInfo.getNewVisibility()), + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true) + ); + conflictDescriptions.putValue(method, message.get()); + if (!needToChangeCalls()) { + iterator.remove(); + } + } + } + } } - } } - } - } + @RequiredReadAction + private void addMethodConflicts(MultiMap conflicts) { + String newMethodName = myChangeInfo.getNewName(); + if (!(myChangeInfo instanceof JavaChangeInfo)) { + return; + } + try { + PsiMethod prototype; + PsiMethod method = myChangeInfo.getMethod(); + if (!JavaLanguage.INSTANCE.equals(method.getLanguage())) { + return; + } + PsiManager manager = method.getManager(); + PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + CanonicalTypes.Type returnType = myChangeInfo.getNewReturnType(); + if (returnType != null) { + prototype = factory.createMethod(newMethodName, returnType.getType(method, manager)); + } + else { + prototype = factory.createConstructor(); + prototype.setName(newMethodName); + } + JavaParameterInfo[] parameters = myChangeInfo.getNewParameters(); - private void addMethodConflicts(MultiMap conflicts) { - String newMethodName = myChangeInfo.getNewName(); - if (!(myChangeInfo instanceof JavaChangeInfo)) { - return; - } - try { - PsiMethod prototype; - final PsiMethod method = myChangeInfo.getMethod(); - if (!JavaLanguage.INSTANCE.equals(method.getLanguage())) { - return; - } - PsiManager manager = method.getManager(); - PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - final CanonicalTypes.Type returnType = myChangeInfo.getNewReturnType(); - if (returnType != null) { - prototype = factory.createMethod(newMethodName, returnType.getType(method, manager)); - } else { - prototype = factory.createConstructor(); - prototype.setName(newMethodName); - } - JavaParameterInfo[] parameters = myChangeInfo.getNewParameters(); + for (JavaParameterInfo info : parameters) { + PsiType parameterType = info.createType(method, manager); + if (parameterType == null) { + parameterType = JavaPsiFacade.getElementFactory(method.getProject()) + .createTypeFromText(JavaClassNames.JAVA_LANG_OBJECT, method); + } + PsiParameter param = factory.createParameter(info.getName(), parameterType); + prototype.getParameterList().add(param); + } - for (JavaParameterInfo info : parameters) { - PsiType parameterType = info.createType(method, manager); - if (parameterType == null) { - parameterType = JavaPsiFacade.getElementFactory(method.getProject()).createTypeFromText(JavaClassNames.JAVA_LANG_OBJECT, method); - } - PsiParameter param = factory.createParameter(info.getName(), parameterType); - prototype.getParameterList().add(param); + ConflictsUtil.checkMethodConflicts(method.getContainingClass(), method, prototype, conflicts); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - - ConflictsUtil.checkMethodConflicts(method.getContainingClass(), method, prototype, conflicts); - } catch (IncorrectOperationException e) { - LOG.error(e); - } } - } - private static class ExpressionList implements ChangeSignatureUtil.ChildrenGenerator { - public static final ExpressionList INSTANCE = new ExpressionList(); + private static class ExpressionList implements ChangeSignatureUtil.ChildrenGenerator { + public static final ExpressionList INSTANCE = new ExpressionList(); - @Override - public List getChildren(PsiExpressionList psiExpressionList) { - return Arrays.asList(psiExpressionList.getExpressions()); + @Override + public List getChildren(PsiExpressionList psiExpressionList) { + return Arrays.asList(psiExpressionList.getExpressions()); + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractClassProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractClassProcessor.java index a41fee354..0edbd24d0 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractClassProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractClassProcessor.java @@ -61,7 +61,7 @@ import consulo.util.collection.ContainerUtil; import consulo.util.collection.MultiMap; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.*; @@ -173,7 +173,7 @@ public PsiClass getCreatedClass() { @Override @RequiredUIAccess - protected boolean preprocessUsages(@Nonnull final Ref refUsages) { + protected boolean preprocessUsages(@Nonnull final SimpleReference refUsages) { final MultiMap conflicts = new MultiMap<>(); myExtractEnumProcessor.findEnumConstantConflicts(refUsages); if (!DestinationFolderComboBox.isAccessible( @@ -294,7 +294,7 @@ protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usa @Override @RequiredReadAction - protected void performRefactoring(UsageInfo[] usageInfos) { + protected void performRefactoring(@Nonnull UsageInfo[] usageInfos) { final PsiClass psiClass = buildClass(); if (psiClass == null) { return; @@ -332,7 +332,7 @@ public void visitReferenceExpression(PsiReferenceExpression expression) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); PsiMethod[] constructors = psiClass.getConstructors(); if (constructors.length == 0) { - final PsiMethod constructor = (PsiMethod)elementFactory.createConstructor().setName(psiClass.getName()); + PsiMethod constructor = (PsiMethod)elementFactory.createConstructor().setName(psiClass.getName()); constructors = new PsiMethod[]{(PsiMethod)psiClass.add(constructor)}; } for (PsiMethod constructor : constructors) { @@ -344,7 +344,7 @@ public void visitReferenceExpression(PsiReferenceExpression expression) { } if (myGenerateAccessors) { - final NecessaryAccessorsVisitor visitor = checkNecessaryGettersSetters4SourceClass(); + NecessaryAccessorsVisitor visitor = checkNecessaryGettersSetters4SourceClass(); for (PsiField field : visitor.getFieldsNeedingGetter()) { sourceClass.add(PropertyUtil.generateGetterPrototype(field)); } @@ -363,7 +363,7 @@ public void visitReferenceExpression(PsiReferenceExpression expression) { } private NecessaryAccessorsVisitor checkNecessaryGettersSetters4SourceClass() { - final NecessaryAccessorsVisitor visitor = new NecessaryAccessorsVisitor() { + NecessaryAccessorsVisitor visitor = new NecessaryAccessorsVisitor() { @Override protected boolean hasGetterOrSetter(PsiMethod[] getters) { for (PsiMethod getter : getters) { @@ -392,7 +392,7 @@ protected boolean isProhibitedReference(PsiField field) { } private NecessaryAccessorsVisitor checkNecessaryGettersSetters4ExtractedClass() { - final NecessaryAccessorsVisitor visitor = new NecessaryAccessorsVisitor() { + NecessaryAccessorsVisitor visitor = new NecessaryAccessorsVisitor() { @Override protected boolean hasGetterOrSetter(PsiMethod[] getters) { for (PsiMethod getter : getters) { @@ -439,16 +439,16 @@ public void visitClass(@Nonnull PsiClass aClass) { @RequiredReadAction private void buildDelegate() { - final PsiManager manager = sourceClass.getManager(); - final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); - final StringBuilder fieldBuffer = new StringBuilder(); - final String delegateVisibility = calculateDelegateVisibility(); + PsiManager manager = sourceClass.getManager(); + PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); + StringBuilder fieldBuffer = new StringBuilder(); + String delegateVisibility = calculateDelegateVisibility(); if (delegateVisibility.length() > 0) { fieldBuffer.append(delegateVisibility).append(' '); } fieldBuffer.append("final "); - final String fullyQualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName); + String fullyQualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName); fieldBuffer.append(fullyQualifiedName); if (!typeParams.isEmpty()) { fieldBuffer.append('<'); @@ -474,9 +474,9 @@ private void buildDelegate() { fieldBuffer.append(");"); try { - final String fieldString = fieldBuffer.toString(); - final PsiField field = factory.createFieldFromText(fieldString, sourceClass); - final PsiElement newField = sourceClass.add(field); + String fieldString = fieldBuffer.toString(); + PsiField field = factory.createFieldFromText(fieldString, sourceClass); + PsiElement newField = sourceClass.add(field); codeStyleManager.reformat(JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(newField)); } catch (IncorrectOperationException e) { @@ -516,7 +516,7 @@ public void findUsages(@Nonnull List usages) { usages.add(new RemoveInnerClass(innerClass)); } for (PsiMethod method : methods) { - if (method.hasModifierProperty(PsiModifier.STATIC)) { + if (method.isStatic()) { findUsagesForStaticMethod(method, usages); } else { @@ -527,19 +527,19 @@ public void findUsages(@Nonnull List usages) { @RequiredReadAction private void findUsagesForInnerClass(PsiClass innerClass, List usages) { - final PsiManager psiManager = innerClass.getManager(); - final Project project = psiManager.getProject(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final Iterable calls = ReferencesSearch.search(innerClass, scope); - final String innerName = innerClass.getQualifiedName(); + PsiManager psiManager = innerClass.getManager(); + Project project = psiManager.getProject(); + GlobalSearchScope scope = GlobalSearchScope.allScope(project); + Iterable calls = ReferencesSearch.search(innerClass, scope); + String innerName = innerClass.getQualifiedName(); assert innerName != null; - final String sourceClassQualifiedName = sourceClass.getQualifiedName(); + String sourceClassQualifiedName = sourceClass.getQualifiedName(); assert sourceClassQualifiedName != null; - final String newInnerClassName = + String newInnerClassName = StringUtil.getQualifiedName(newPackageName, newClassName) + innerName.substring(sourceClassQualifiedName.length()); boolean hasExternalReference = false; for (PsiReference reference : calls) { - final PsiElement referenceElement = reference.getElement(); + PsiElement referenceElement = reference.getElement(); if (referenceElement instanceof PsiJavaCodeReferenceElement javaCodeReferenceElement) { if (!isInMovedElement(referenceElement)) { usages.add(new ReplaceClassReference(javaCodeReferenceElement, newInnerClassName)); @@ -554,17 +554,17 @@ private void findUsagesForInnerClass(PsiClass innerClass, List @RequiredReadAction private void findUsagesForMethod(PsiMethod method, List usages) { - final PsiManager psiManager = method.getManager(); - final Project project = psiManager.getProject(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final Iterable calls = ReferencesSearch.search(method, scope); + PsiManager psiManager = method.getManager(); + Project project = psiManager.getProject(); + GlobalSearchScope scope = GlobalSearchScope.allScope(project); + Iterable calls = ReferencesSearch.search(method, scope); for (PsiReference reference : calls) { if (reference.getElement().getParent() instanceof PsiMethodCallExpression call) { if (isInMovedElement(call)) { continue; } - final PsiReferenceExpression methodExpression = call.getMethodExpression(); - final PsiExpression qualifier = methodExpression.getQualifierExpression(); + PsiReferenceExpression methodExpression = call.getMethodExpression(); + PsiExpression qualifier = methodExpression.getQualifierExpression(); if (qualifier == null || qualifier instanceof PsiThisExpression) { usages.add(new ReplaceThisCallWithDelegateCall(call, delegateFieldName)); } @@ -586,22 +586,22 @@ private void findUsagesForMethod(PsiMethod method, List usages @RequiredReadAction private void findUsagesForStaticMethod(PsiMethod method, List usages) { - final PsiManager psiManager = method.getManager(); - final Project project = psiManager.getProject(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final Iterable calls = ReferencesSearch.search(method, scope); - final String fullyQualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName); + PsiManager psiManager = method.getManager(); + Project project = psiManager.getProject(); + GlobalSearchScope scope = GlobalSearchScope.allScope(project); + Iterable calls = ReferencesSearch.search(method, scope); + String fullyQualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName); for (PsiReference reference : calls) { - final PsiElement referenceElement = reference.getElement(); + PsiElement referenceElement = reference.getElement(); - final PsiElement parent = referenceElement.getParent(); + PsiElement parent = referenceElement.getParent(); if (parent instanceof PsiMethodCallExpression call) { if (!isInMovedElement(call)) { usages.add(new RetargetStaticMethodCall(call, fullyQualifiedName)); } } else if (parent instanceof PsiImportStaticStatement psiImportStatic) { - final PsiJavaCodeReferenceElement importReference = psiImportStatic.getImportReference(); + PsiJavaCodeReferenceElement importReference = psiImportStatic.getImportReference(); if (importReference != null && importReference.getQualifier() instanceof PsiJavaCodeReferenceElement qualifier) { usages.add(new ReplaceClassReference(qualifier, fullyQualifiedName)); } @@ -626,17 +626,17 @@ private boolean isInMovedElement(PsiElement exp) { @RequiredReadAction private void findUsagesForField(PsiField field, List usages) { - final PsiManager psiManager = field.getManager(); - final Project project = psiManager.getProject(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + PsiManager psiManager = field.getManager(); + Project project = psiManager.getProject(); + GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final String qualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName); + String qualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName); String getter = null; if (myGenerateAccessors) { getter = PropertyUtil.suggestGetterName(field); } else { - final PsiMethod fieldGetter = PropertyUtil.findPropertyGetter(sourceClass, field.getName(), false, false); + PsiMethod fieldGetter = PropertyUtil.findPropertyGetter(sourceClass, field.getName(), false, false); if (fieldGetter != null && isInMovedElement(fieldGetter)) { getter = fieldGetter.getName(); } @@ -647,15 +647,15 @@ private void findUsagesForField(PsiField field, List usages) { setter = PropertyUtil.suggestSetterName(field); } else { - final PsiMethod fieldSetter = PropertyUtil.findPropertySetter(sourceClass, field.getName(), false, false); + PsiMethod fieldSetter = PropertyUtil.findPropertySetter(sourceClass, field.getName(), false, false); if (fieldSetter != null && isInMovedElement(fieldSetter)) { setter = fieldSetter.getName(); } } - final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); + boolean isStatic = field.isStatic(); for (PsiReference reference : ReferencesSearch.search(field, scope)) { - final PsiElement element = reference.getElement(); + PsiElement element = reference.getElement(); if (isInMovedElement(element)) { continue; } @@ -672,12 +672,14 @@ else if (RefactoringUtil.isAssignmentLHS(exp)) { usages.add( isStatic ? new ReplaceStaticVariableAssignment(exp, qualifiedName) - : new ReplaceInstanceVariableAssignment(PsiTreeUtil.getParentOfType(exp, PsiAssignmentExpression.class), - delegateFieldName, - setter, - getter, - field.getName() - )); + : new ReplaceInstanceVariableAssignment( + PsiTreeUtil.getParentOfType(exp, PsiAssignmentExpression.class), + delegateFieldName, + setter, + getter, + field.getName() + ) + ); } else { usages.add( @@ -699,9 +701,9 @@ else if (element instanceof PsiDocTagValue) { @RequiredReadAction private PsiClass buildClass() { - final PsiManager manager = sourceClass.getManager(); - final Project project = sourceClass.getProject(); - final ExtractedClassBuilder extractedClassBuilder = new ExtractedClassBuilder(); + PsiManager manager = sourceClass.getManager(); + Project project = sourceClass.getProject(); + ExtractedClassBuilder extractedClassBuilder = new ExtractedClassBuilder(); extractedClassBuilder.setProject(myProject); extractedClassBuilder.setClassName(newClassName); extractedClassBuilder.setPackageName(newPackageName); @@ -718,36 +720,36 @@ private PsiClass buildClass() { extractedClassBuilder.addInnerClass(innerClass, innerClassesToMakePublic.contains(innerClass)); } extractedClassBuilder.setTypeArguments(typeParams); - final List interfaces = calculateInterfacesSupported(); + List interfaces = calculateInterfacesSupported(); extractedClassBuilder.setInterfaces(interfaces); if (myGenerateAccessors) { - final NecessaryAccessorsVisitor visitor = checkNecessaryGettersSetters4ExtractedClass(); + NecessaryAccessorsVisitor visitor = checkNecessaryGettersSetters4ExtractedClass(); sourceClass.accept(visitor); extractedClassBuilder.setFieldsNeedingGetters(visitor.getFieldsNeedingGetter()); extractedClassBuilder.setFieldsNeedingSetters(visitor.getFieldsNeedingSetter()); } - final String classString = extractedClassBuilder.buildBeanClass(); + String classString = extractedClassBuilder.buildBeanClass(); try { - final PsiFile containingFile = sourceClass.getContainingFile(); - final PsiDirectory directory; - final PsiDirectory containingDirectory = containingFile.getContainingDirectory(); + PsiFile containingFile = sourceClass.getContainingFile(); + PsiDirectory directory; + PsiDirectory containingDirectory = containingFile.getContainingDirectory(); if (myMoveDestination != null) { directory = myMoveDestination.getTargetDirectory(containingDirectory); } else { - final Module module = ModuleUtil.findModuleForPsiElement(containingFile); + Module module = ModuleUtil.findModuleForPsiElement(containingFile); assert module != null; directory = PackageUtil.findOrCreateDirectoryForPackage(module, newPackageName, containingDirectory, false, true); } if (directory != null) { - final PsiFileFactory factory = PsiFileFactory.getInstance(project); - final PsiFile newFile = factory.createFileFromText(newClassName + ".java", JavaFileType.INSTANCE, classString); - final PsiElement addedFile = directory.add(newFile); - final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); - final PsiElement shortenedFile = JavaCodeStyleManager.getInstance(project).shortenClassReferences(addedFile); + PsiFileFactory factory = PsiFileFactory.getInstance(project); + PsiFile newFile = factory.createFileFromText(newClassName + ".java", JavaFileType.INSTANCE, classString); + PsiElement addedFile = directory.add(newFile); + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); + PsiElement shortenedFile = JavaCodeStyleManager.getInstance(project).shortenClassReferences(addedFile); return ((PsiJavaFile)codeStyleManager.reformat(shortenedFile)).getClasses()[0]; } else { @@ -760,13 +762,13 @@ private PsiClass buildClass() { } private List calculateInterfacesSupported() { - final List out = new ArrayList<>(); - final PsiClass[] supers = sourceClass.getSupers(); + List out = new ArrayList<>(); + PsiClass[] supers = sourceClass.getSupers(); for (PsiClass superClass : supers) { if (!superClass.isInterface()) { continue; } - final PsiMethod[] superclassMethods = superClass.getMethods(); + PsiMethod[] superclassMethods = superClass.getMethods(); if (superclassMethods.length == 0) { continue; } @@ -789,22 +791,22 @@ private List calculateInterfacesSupported() { out.add(superClass); } } - final Project project = sourceClass.getProject(); - final PsiManager manager = sourceClass.getManager(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + Project project = sourceClass.getProject(); + PsiManager manager = sourceClass.getManager(); + GlobalSearchScope scope = GlobalSearchScope.allScope(project); if (usesDefaultSerialization(sourceClass)) { - final PsiClass serializable = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.io.Serializable", scope); + PsiClass serializable = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.io.Serializable", scope); out.add(serializable); } if (usesDefaultClone(sourceClass)) { - final PsiClass cloneable = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Cloneable", scope); + PsiClass cloneable = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Cloneable", scope); out.add(cloneable); } return out; } private static boolean isSuperMethod(PsiMethod method, PsiMethod movedMethod) { - final PsiMethod[] superMethods = movedMethod.findSuperMethods(); + PsiMethod[] superMethods = movedMethod.findSuperMethods(); for (PsiMethod testMethod : superMethods) { if (testMethod.equals(method)) { return true; @@ -814,17 +816,17 @@ private static boolean isSuperMethod(PsiMethod method, PsiMethod movedMethod) { } private static boolean usesDefaultClone(PsiClass aClass) { - final Project project = aClass.getProject(); - final PsiManager manager = aClass.getManager(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final PsiClass cloneable = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Cloneable", scope); + Project project = aClass.getProject(); + PsiManager manager = aClass.getManager(); + GlobalSearchScope scope = GlobalSearchScope.allScope(project); + PsiClass cloneable = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Cloneable", scope); if (!InheritanceUtil.isInheritorOrSelf(aClass, cloneable, true)) { return false; } - final PsiMethod[] methods = aClass.findMethodsByName("clone", false); + PsiMethod[] methods = aClass.findMethodsByName("clone", false); for (PsiMethod method : methods) { - final PsiParameterList parameterList = method.getParameterList(); - final PsiParameter[] parameters = parameterList.getParameters(); + PsiParameterList parameterList = method.getParameterList(); + PsiParameter[] parameters = parameterList.getParameters(); if (parameters.length == 0) { return false; } @@ -833,20 +835,20 @@ private static boolean usesDefaultClone(PsiClass aClass) { } private static boolean usesDefaultSerialization(PsiClass aClass) { - final Project project = aClass.getProject(); - final PsiManager manager = aClass.getManager(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final PsiClass serializable = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.io.Serializable", scope); + Project project = aClass.getProject(); + PsiManager manager = aClass.getManager(); + GlobalSearchScope scope = GlobalSearchScope.allScope(project); + PsiClass serializable = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.io.Serializable", scope); if (!InheritanceUtil.isInheritorOrSelf(aClass, serializable, true)) { return false; } - final PsiMethod[] methods = aClass.findMethodsByName("writeObject", false); + PsiMethod[] methods = aClass.findMethodsByName("writeObject", false); for (PsiMethod method : methods) { - final PsiParameterList parameterList = method.getParameterList(); - final PsiParameter[] parameters = parameterList.getParameters(); + PsiParameterList parameterList = method.getParameterList(); + PsiParameter[] parameters = parameterList.getParameters(); if (parameters.length == 1) { - final PsiType type = parameters[0].getType(); - final String text = type.getCanonicalText(); + PsiType type = parameters[0].getType(); + String text = type.getCanonicalText(); if ("java.io.DataOutputStream".equals(text)) { return false; } @@ -864,7 +866,7 @@ private abstract class NecessaryAccessorsVisitor extends JavaRecursiveElementWal public void visitReferenceExpression(PsiReferenceExpression expression) { super.visitReferenceExpression(expression); if (isProhibitedReference(expression)) { - final PsiField field = getReferencedField(expression); + PsiField field = getReferencedField(expression); if (!hasGetter(field) && !(field.isStatic() && field.isFinal()) && !field.isPublic()) { fieldsNeedingGetter.add(field); } @@ -876,9 +878,9 @@ public void visitReferenceExpression(PsiReferenceExpression expression) { public void visitAssignmentExpression(@Nonnull PsiAssignmentExpression expression) { super.visitAssignmentExpression(expression); - final PsiExpression lhs = expression.getLExpression(); + PsiExpression lhs = expression.getLExpression(); if (isProhibitedReference(lhs)) { - final PsiField field = getReferencedField(lhs); + PsiField field = getReferencedField(lhs); if (!hasGetter(field) && !(field.isStatic() && field.isFinal()) && !field.isPublic()) { fieldsNeedingSetter.add(field); } @@ -900,13 +902,13 @@ public void visitPrefixExpression(@Nonnull PsiPrefixExpression expression) { } @RequiredReadAction - private void checkSetterNeeded(final PsiExpression operand, final PsiJavaToken sign) { - final IElementType tokenType = sign.getTokenType(); + private void checkSetterNeeded(PsiExpression operand, PsiJavaToken sign) { + IElementType tokenType = sign.getTokenType(); if (!tokenType.equals(JavaTokenType.PLUSPLUS) && !tokenType.equals(JavaTokenType.MINUSMINUS)) { return; } if (isProhibitedReference(operand)) { - final PsiField field = getReferencedField(operand); + PsiField field = getReferencedField(operand); if (!hasSetter(field) && !(field.isStatic() && field.isFinal())) { fieldsNeedingSetter.add(field); } @@ -921,15 +923,15 @@ public Set getFieldsNeedingSetter() { return fieldsNeedingSetter; } - private boolean hasGetter(final PsiField field) { + private boolean hasGetter(PsiField field) { return hasGetterOrSetter(sourceClass.findMethodsBySignature(PropertyUtil.generateGetterPrototype(field), false)); } - private boolean hasSetter(final PsiField field) { + private boolean hasSetter(PsiField field) { return hasGetterOrSetter(sourceClass.findMethodsBySignature(PropertyUtil.generateSetterPrototype(field), false)); } - protected abstract boolean hasGetterOrSetter(final PsiMethod[] getters); + protected abstract boolean hasGetterOrSetter(PsiMethod[] getters); protected boolean isProhibitedReference(PsiExpression expression) { return BackpointerUtil.isBackpointerReference(expression, NecessaryAccessorsVisitor.this::isProhibitedReference); diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractEnumProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractEnumProcessor.java index c3baf35e0..552faf9ed 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractEnumProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractEnumProcessor.java @@ -4,245 +4,202 @@ package com.intellij.java.impl.refactoring.extractclass; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - import com.intellij.java.impl.codeInsight.generation.GenerateMembersUtil; -import com.intellij.java.language.psi.*; -import consulo.project.Project; -import consulo.util.lang.ref.Ref; -import consulo.util.lang.StringUtil; -import consulo.language.psi.*; -import consulo.language.psi.scope.GlobalSearchScope; -import consulo.language.psi.util.PsiTreeUtil; -import consulo.language.psi.PsiUtilCore; import com.intellij.java.impl.refactoring.extractclass.usageInfo.ReplaceStaticVariableAccess; import com.intellij.java.impl.refactoring.psi.MutationUtils; import com.intellij.java.impl.refactoring.typeMigration.TypeMigrationProcessor; import com.intellij.java.impl.refactoring.typeMigration.TypeMigrationRules; import com.intellij.java.impl.refactoring.util.EnumConstantsUtil; import com.intellij.java.impl.refactoring.util.FixableUsageInfo; +import com.intellij.java.language.psi.*; +import consulo.annotation.access.RequiredReadAction; import consulo.language.editor.refactoring.ui.RefactoringUIUtil; +import consulo.language.psi.PsiElement; +import consulo.language.psi.PsiUtilCore; +import consulo.language.psi.scope.GlobalSearchScope; +import consulo.language.psi.util.PsiTreeUtil; +import consulo.language.util.IncorrectOperationException; +import consulo.project.Project; import consulo.usage.UsageInfo; +import consulo.util.lang.StringUtil; import consulo.util.lang.function.Functions; -import consulo.language.util.IncorrectOperationException; - -public class ExtractEnumProcessor -{ - private final Project myProject; - private final List myEnumConstants; - private final PsiClass myClass; - - private TypeMigrationProcessor myTypeMigrationProcessor; - - public ExtractEnumProcessor(Project project, List enumConstants, PsiClass aClass) - { - myProject = project; - myEnumConstants = enumConstants; - myClass = aClass; - } - - - public void findEnumConstantConflicts(final Ref refUsages) - { - if(hasUsages2Migrate()) - { - final List resolvableConflicts = new ArrayList<>(); - for(UsageInfo failedUsage : myTypeMigrationProcessor.getLabeler().getFailedUsages()) - { - final PsiElement element = failedUsage.getElement(); - if(element instanceof PsiReferenceExpression) - { - resolvableConflicts.add(new FixableUsageInfo(element) - { - @Override - public void fixUsage() throws IncorrectOperationException - { - final PsiReferenceExpression expression = (PsiReferenceExpression) element; - final String link = GenerateMembersUtil.suggestGetterName("value", expression.getType(), myProject) + "()"; - MutationUtils.replaceExpression(expression.getReferenceName() + "." + link, expression); - } - }); - } - else if(element != null) - { - resolvableConflicts.add(new ConflictUsageInfo(element, null)); - } - } - if(!resolvableConflicts.isEmpty()) - { - final List usageInfos = new ArrayList<>(Arrays.asList(refUsages.get())); - for(Iterator iterator = resolvableConflicts.iterator(); iterator.hasNext(); ) - { - final UsageInfo conflict = iterator.next(); - for(UsageInfo usageInfo : usageInfos) - { - if(conflict.getElement() == usageInfo.getElement()) - { - iterator.remove(); - break; - } - } - } - resolvableConflicts.addAll(0, usageInfos); - refUsages.set(resolvableConflicts.toArray(UsageInfo.EMPTY_ARRAY)); - } - } - } - - private boolean hasUsages2Migrate() - { - return myTypeMigrationProcessor != null; - } - - public List findEnumConstantUsages(List fieldUsages) - { - final List result = new ArrayList<>(); - if(!myEnumConstants.isEmpty()) - { - final Set switchStatements = new HashSet<>(); - for(UsageInfo usage : fieldUsages) - { - if(usage instanceof ReplaceStaticVariableAccess) - { - final PsiElement element = usage.getElement(); - final PsiSwitchStatement switchStatement = PsiTreeUtil.getParentOfType(element, PsiSwitchStatement.class); - if(switchStatement != null) - { - switchStatements.add(switchStatement); - } - } - } - - final PsiConstantEvaluationHelper evaluationHelper = JavaPsiFacade.getInstance(myProject).getConstantEvaluationHelper(); - final Set enumValues = new HashSet<>(); - for(PsiField enumConstant : myEnumConstants) - { - enumValues.add(evaluationHelper.computeConstantExpression(enumConstant.getInitializer())); - } - final PsiType enumValueType = myEnumConstants.get(0).getType(); - - for(PsiSwitchStatement switchStatement : switchStatements) - { - final PsiStatement errStatement = EnumConstantsUtil.isEnumSwitch(switchStatement, enumValueType, enumValues); - if(errStatement != null) - { - String description = null; - if(errStatement instanceof PsiSwitchLabelStatement) - { - final PsiExpression caseValue = ((PsiSwitchLabelStatement) errStatement).getCaseValue(); - if(caseValue != null) - { - description = caseValue.getText() + " can not be replaced with enum"; - } - } - result.add(new ConflictUsageInfo(errStatement, description)); - - } - else - { - final PsiExpression expression = switchStatement.getExpression(); - if(expression instanceof PsiReferenceExpression) - { - final PsiElement element = ((PsiReferenceExpression) expression).resolve(); - if(element != null) - { - if(!element.getManager().isInProject(element)) - { - result.add(new ConflictUsageInfo(expression, StringUtil.capitalize(RefactoringUIUtil.getDescription(element, false)) + " is out of project")); - } - } - } - else - { - result.add(new ConflictUsageInfo(expression, null)); - } - } - } - - final TypeMigrationRules rules = new TypeMigrationRules(myProject); - rules.addConversionDescriptor(new EnumTypeConversionRule(myEnumConstants)); - rules.setBoundScope(GlobalSearchScope.projectScope(myProject)); - myTypeMigrationProcessor = new TypeMigrationProcessor(myProject, PsiUtilCore.toPsiElementArray(myEnumConstants), Functions.constant(JavaPsiFacade.getElementFactory(myProject).createType - (myClass)), rules, true); - for(UsageInfo usageInfo : myTypeMigrationProcessor.findUsages()) - { - final PsiElement migrateElement = usageInfo.getElement(); - if(migrateElement instanceof PsiField) - { - final PsiField enumConstantField = (PsiField) migrateElement; - if(enumConstantField.hasModifierProperty(PsiModifier.STATIC) && enumConstantField.hasModifierProperty(PsiModifier.FINAL) && enumConstantField.hasInitializer() && !myEnumConstants - .contains(enumConstantField)) - { - continue; - } - } - result.add(new EnumTypeMigrationUsageInfo(usageInfo)); - } - } - return result; - } - - public void performEnumConstantTypeMigration(UsageInfo[] usageInfos) - { - if(hasUsages2Migrate()) - { - final List migrationInfos = new ArrayList<>(); - for(UsageInfo usageInfo : usageInfos) - { - if(usageInfo instanceof EnumTypeMigrationUsageInfo) - { - migrationInfos.add(((EnumTypeMigrationUsageInfo) usageInfo).getUsageInfo()); - } - } - myTypeMigrationProcessor.performRefactoring(migrationInfos.toArray(UsageInfo.EMPTY_ARRAY)); - } - } - - private static class EnumTypeMigrationUsageInfo extends FixableUsageInfo - { - private final UsageInfo myUsageInfo; - - public EnumTypeMigrationUsageInfo(UsageInfo usageInfo) - { - super(usageInfo.getElement()); - myUsageInfo = usageInfo; - } - - @Override - public void fixUsage() throws IncorrectOperationException - { - } - - public UsageInfo getUsageInfo() - { - return myUsageInfo; - } - } - - private static class ConflictUsageInfo extends FixableUsageInfo - { - private final String myDescription; - - public ConflictUsageInfo(PsiElement expression, String description) - { - super(expression); - myDescription = description; - } - - @Override - public void fixUsage() throws IncorrectOperationException - { - } - - @Override - public String getConflictMessage() - { - return "Unable to migrate statement to enum constant." + (myDescription != null ? " " + myDescription : ""); - } - } +import consulo.util.lang.ref.SimpleReference; + +import java.util.*; + +public class ExtractEnumProcessor { + private final Project myProject; + private final List myEnumConstants; + private final PsiClass myClass; + + private TypeMigrationProcessor myTypeMigrationProcessor; + + public ExtractEnumProcessor(Project project, List enumConstants, PsiClass aClass) { + myProject = project; + myEnumConstants = enumConstants; + myClass = aClass; + } + + @RequiredReadAction + public void findEnumConstantConflicts(SimpleReference refUsages) { + if (hasUsages2Migrate()) { + List resolvableConflicts = new ArrayList<>(); + for (UsageInfo failedUsage : myTypeMigrationProcessor.getLabeler().getFailedUsages()) { + PsiElement element = failedUsage.getElement(); + if (element instanceof PsiReferenceExpression) { + resolvableConflicts.add(new FixableUsageInfo(element) { + @Override + public void fixUsage() throws IncorrectOperationException { + PsiReferenceExpression expression = (PsiReferenceExpression)element; + String link = GenerateMembersUtil.suggestGetterName("value", expression.getType(), myProject) + "()"; + MutationUtils.replaceExpression(expression.getReferenceName() + "." + link, expression); + } + }); + } + else if (element != null) { + resolvableConflicts.add(new ConflictUsageInfo(element, null)); + } + } + if (!resolvableConflicts.isEmpty()) { + List usageInfos = new ArrayList<>(Arrays.asList(refUsages.get())); + for (Iterator iterator = resolvableConflicts.iterator(); iterator.hasNext(); ) { + UsageInfo conflict = iterator.next(); + for (UsageInfo usageInfo : usageInfos) { + if (conflict.getElement() == usageInfo.getElement()) { + iterator.remove(); + break; + } + } + } + resolvableConflicts.addAll(0, usageInfos); + refUsages.set(resolvableConflicts.toArray(UsageInfo.EMPTY_ARRAY)); + } + } + } + + private boolean hasUsages2Migrate() { + return myTypeMigrationProcessor != null; + } + + @RequiredReadAction + public List findEnumConstantUsages(List fieldUsages) { + List result = new ArrayList<>(); + if (!myEnumConstants.isEmpty()) { + Set switchStatements = new HashSet<>(); + for (UsageInfo usage : fieldUsages) { + if (usage instanceof ReplaceStaticVariableAccess) { + PsiElement element = usage.getElement(); + PsiSwitchStatement switchStatement = PsiTreeUtil.getParentOfType(element, PsiSwitchStatement.class); + if (switchStatement != null) { + switchStatements.add(switchStatement); + } + } + } + + PsiConstantEvaluationHelper evaluationHelper = JavaPsiFacade.getInstance(myProject).getConstantEvaluationHelper(); + Set enumValues = new HashSet<>(); + for (PsiField enumConstant : myEnumConstants) { + enumValues.add(evaluationHelper.computeConstantExpression(enumConstant.getInitializer())); + } + PsiType enumValueType = myEnumConstants.get(0).getType(); + + for (PsiSwitchStatement switchStatement : switchStatements) { + PsiStatement errStatement = EnumConstantsUtil.isEnumSwitch(switchStatement, enumValueType, enumValues); + if (errStatement != null) { + String description = null; + if (errStatement instanceof PsiSwitchLabelStatement switchLabelStmt) { + PsiExpression caseValue = switchLabelStmt.getCaseValue(); + if (caseValue != null) { + description = caseValue.getText() + " can not be replaced with enum"; + } + } + result.add(new ConflictUsageInfo(errStatement, description)); + } + else { + PsiExpression expression = switchStatement.getExpression(); + if (expression instanceof PsiReferenceExpression refExpr) { + PsiElement element = refExpr.resolve(); + if (element != null && !element.getManager().isInProject(element)) { + result.add(new ConflictUsageInfo( + expression, + StringUtil.capitalize(RefactoringUIUtil.getDescription(element, false)) + " is out of project" + )); + } + } + else { + result.add(new ConflictUsageInfo(expression, null)); + } + } + } + + TypeMigrationRules rules = new TypeMigrationRules(myProject); + rules.addConversionDescriptor(new EnumTypeConversionRule(myEnumConstants)); + rules.setBoundScope(GlobalSearchScope.projectScope(myProject)); + myTypeMigrationProcessor = new TypeMigrationProcessor( + myProject, + PsiUtilCore.toPsiElementArray(myEnumConstants), + Functions.constant(JavaPsiFacade.getElementFactory(myProject).createType(myClass)), + rules, + true + ); + for (UsageInfo usageInfo : myTypeMigrationProcessor.findUsages()) { + PsiElement migrateElement = usageInfo.getElement(); + if (migrateElement instanceof PsiField enumConstantField) { + if (enumConstantField.isStatic() && enumConstantField.isFinal() + && enumConstantField.hasInitializer() && !myEnumConstants.contains(enumConstantField)) { + continue; + } + } + result.add(new EnumTypeMigrationUsageInfo(usageInfo)); + } + } + return result; + } + + public void performEnumConstantTypeMigration(UsageInfo[] usageInfos) { + if (hasUsages2Migrate()) { + List migrationInfos = new ArrayList<>(); + for (UsageInfo usageInfo : usageInfos) { + if (usageInfo instanceof EnumTypeMigrationUsageInfo enumTypeMigrationUsageInfo) { + migrationInfos.add(enumTypeMigrationUsageInfo.getUsageInfo()); + } + } + myTypeMigrationProcessor.performRefactoring(migrationInfos.toArray(UsageInfo.EMPTY_ARRAY)); + } + } + + private static class EnumTypeMigrationUsageInfo extends FixableUsageInfo { + private final UsageInfo myUsageInfo; + + public EnumTypeMigrationUsageInfo(UsageInfo usageInfo) { + super(usageInfo.getElement()); + myUsageInfo = usageInfo; + } + + @Override + public void fixUsage() throws IncorrectOperationException { + } + + public UsageInfo getUsageInfo() { + return myUsageInfo; + } + } + + private static class ConflictUsageInfo extends FixableUsageInfo { + private final String myDescription; + + public ConflictUsageInfo(PsiElement expression, String description) { + super(expression); + myDescription = description; + } + + @Override + public void fixUsage() throws IncorrectOperationException { + } + + @Override + public String getConflictMessage() { + return "Unable to migrate statement to enum constant." + (myDescription != null ? " " + myDescription : ""); + } + } } \ No newline at end of file diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineConstantFieldProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineConstantFieldProcessor.java index 4bc5807d4..554d7651d 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineConstantFieldProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineConstantFieldProcessor.java @@ -20,6 +20,7 @@ import com.intellij.java.language.impl.psi.impl.source.javadoc.PsiDocMethodOrFieldRef; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiUtil; +import consulo.annotation.access.RequiredReadAction; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.rename.NonCodeUsageInfoFactory; @@ -37,12 +38,13 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.NonCodeUsageInfo; import consulo.usage.UsageInfo; import consulo.usage.UsageInfoFactory; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.*; @@ -50,349 +52,301 @@ /** * @author ven */ -public class InlineConstantFieldProcessor extends BaseRefactoringProcessor -{ - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.inline" + - ".InlineConstantFieldProcessor"); - private PsiField myField; - private final PsiReferenceExpression myRefExpr; - private final boolean myInlineThisOnly; - private final boolean mySearchInCommentsAndStrings; - private final boolean mySearchForTextOccurrences; - - public InlineConstantFieldProcessor(PsiField field, - Project project, - PsiReferenceExpression ref, - boolean isInlineThisOnly) - { - this(field, project, ref, isInlineThisOnly, false, false); - } - - public InlineConstantFieldProcessor(PsiField field, - Project project, - PsiReferenceExpression ref, - boolean isInlineThisOnly, - boolean searchInCommentsAndStrings, - boolean searchForTextOccurrences) - { - super(project); - myField = field; - myRefExpr = ref; - myInlineThisOnly = isInlineThisOnly; - mySearchInCommentsAndStrings = searchInCommentsAndStrings; - mySearchForTextOccurrences = searchForTextOccurrences; - } - - @Override - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) - { - return new InlineViewDescriptor(myField); - } - - @Override - protected boolean isPreviewUsages(@Nonnull UsageInfo[] usages) - { - if (super.isPreviewUsages(usages)) - { - return true; - } - for (UsageInfo info : usages) - { - if (info instanceof NonCodeUsageInfo) - { - return true; - } - } - return false; - } - - private static class UsageFromJavaDoc extends UsageInfo - { - private UsageFromJavaDoc(@Nonnull PsiElement element) - { - super(element, true); - } - } - - @Override - @Nonnull - protected UsageInfo[] findUsages() - { - if (myInlineThisOnly) - { - return new UsageInfo[]{new UsageInfo(myRefExpr)}; - } - - List usages = new ArrayList(); - for (PsiReference ref : ReferencesSearch.search(myField, GlobalSearchScope.projectScope(myProject), false)) - { - PsiElement element = ref.getElement(); - UsageInfo info = new UsageInfo(element); - - if (!(element instanceof PsiExpression) && PsiTreeUtil.getParentOfType(element, - PsiImportStaticStatement.class) == null) - { - info = new UsageFromJavaDoc(element); - } - - usages.add(info); - } - if (mySearchInCommentsAndStrings || mySearchForTextOccurrences) - { - UsageInfoFactory nonCodeUsageFactory = new NonCodeUsageInfoFactory(myField, myField.getName()) - { - @Override - public UsageInfo createUsageInfo(@Nonnull PsiElement usage, int startOffset, int endOffset) - { - if (PsiTreeUtil.isAncestor(myField, usage, false)) - { - return null; - } - return super.createUsageInfo(usage, startOffset, endOffset); - } - }; - if (mySearchInCommentsAndStrings) - { - String stringToSearch = ElementDescriptionUtil.getElementDescription(myField, - NonCodeSearchDescriptionLocation.STRINGS_AND_COMMENTS); - TextOccurrencesUtil.addUsagesInStringsAndComments(myField, stringToSearch, usages, - nonCodeUsageFactory); - } - - if (mySearchForTextOccurrences) - { - String stringToSearch = ElementDescriptionUtil.getElementDescription(myField, - NonCodeSearchDescriptionLocation.NON_JAVA); - TextOccurrencesUtil.addTextOccurences(myField, stringToSearch, GlobalSearchScope.projectScope - (myProject), usages, nonCodeUsageFactory); - } - } - return usages.toArray(new UsageInfo[usages.size()]); - } - - @Override - protected void refreshElements(@Nonnull PsiElement[] elements) - { - LOG.assertTrue(elements.length == 1 && elements[0] instanceof PsiField); - myField = (PsiField) elements[0]; - } - - @Override - protected void performRefactoring(@Nonnull UsageInfo[] usages) - { - PsiExpression initializer = myField.getInitializer(); - LOG.assertTrue(initializer != null); - - initializer = normalize((PsiExpression) initializer.copy()); - for (UsageInfo info : usages) - { - if (info instanceof UsageFromJavaDoc) - { - continue; - } - if (info instanceof NonCodeUsageInfo) - { - continue; - } - final PsiElement element = info.getElement(); - if (element == null) - { - continue; - } - try - { - if (element instanceof PsiExpression) - { - inlineExpressionUsage((PsiExpression) element, initializer); - } - else - { - PsiImportStaticStatement importStaticStatement = PsiTreeUtil.getParentOfType(element, - PsiImportStaticStatement.class); - LOG.assertTrue(importStaticStatement != null, element.getText()); - importStaticStatement.delete(); - } - } - catch (IncorrectOperationException e) - { - LOG.error(e); - } - } - - if (!myInlineThisOnly) - { - try - { - myField.delete(); - } - catch (IncorrectOperationException e) - { - LOG.error(e); - } - } - } - - /*@Nullable - @Override - protected RefactoringEventData getBeforeData() - { - RefactoringEventData data = new RefactoringEventData(); - data.addElement(myField); - return data; - } - - @Nullable - @Override - protected String getRefactoringId() - { - return "refactoring.inline.field"; - } */ - - private void inlineExpressionUsage(PsiExpression expr, - PsiExpression initializer1) throws IncorrectOperationException - { - if (myField.isWritable()) - { - myField.normalizeDeclaration(); - } - if (expr instanceof PsiReferenceExpression) - { - PsiExpression qExpression = ((PsiReferenceExpression) expr).getQualifierExpression(); - if (qExpression != null) - { - PsiReferenceExpression referenceExpression = null; - if (initializer1 instanceof PsiReferenceExpression) - { - referenceExpression = (PsiReferenceExpression) initializer1; - } - else if (initializer1 instanceof PsiMethodCallExpression) - { - referenceExpression = ((PsiMethodCallExpression) initializer1).getMethodExpression(); - } - if (referenceExpression != null && - referenceExpression.getQualifierExpression() == null && - !(referenceExpression.advancedResolve(false).getCurrentFileResolveScope() instanceof - PsiImportStaticStatement)) - { - referenceExpression.setQualifierExpression(qExpression); - } - } - } - - InlineUtil.inlineVariable(myField, initializer1, (PsiJavaCodeReferenceElement) expr); - } - - private static PsiExpression normalize(PsiExpression expression) - { - if (expression instanceof PsiArrayInitializerExpression) - { - PsiElementFactory factory = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory(); - try - { - final PsiType type = expression.getType(); - if (type != null) - { - String typeString = type.getCanonicalText(); - PsiNewExpression result = (PsiNewExpression) factory.createExpressionFromText("new " + typeString - + "{}", expression); - result.getArrayInitializer().replace(expression); - return result; - } - } - catch (IncorrectOperationException e) - { - LOG.error(e); - return expression; - } - } - - return expression; - } - - @Override - protected String getCommandName() - { - return RefactoringLocalize.inlineFieldCommand(DescriptiveNameUtil.getDescriptiveName(myField)).get(); - } - - @Override - protected boolean preprocessUsages(@Nonnull Ref refUsages) - { - UsageInfo[] usagesIn = refUsages.get(); - MultiMap conflicts = new MultiMap(); - - ReferencedElementsCollector collector = new ReferencedElementsCollector(); - PsiExpression initializer = myField.getInitializer(); - LOG.assertTrue(initializer != null); - initializer.accept(collector); - HashSet referencedWithVisibility = collector.myReferencedMembers; - - PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myField.getProject()).getResolveHelper(); - for (UsageInfo info : usagesIn) - { - PsiElement element = info.getElement(); - if (element instanceof PsiExpression expression && isAccessedForWriting(expression)) - { - LocalizeValue message = RefactoringLocalize.zeroIsUsedForWritingIn1( - RefactoringUIUtil.getDescription(myField, true), - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true) - ); - conflicts.putValue(element, message.get()); - } - - for (PsiMember member : referencedWithVisibility) - { - if (!resolveHelper.isAccessible(member, element, null)) - { - LocalizeValue message = RefactoringLocalize.zeroWillNotBeAccessibleFrom1AfterInlining( - RefactoringUIUtil.getDescription(member, true), - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true) - ); - conflicts.putValue(member, message.get()); - } - } - } - - if (!myInlineThisOnly) - { - for (UsageInfo info : usagesIn) - { - if (info instanceof UsageFromJavaDoc) - { - final PsiElement element = info.getElement(); - if (element instanceof PsiDocMethodOrFieldRef && !PsiTreeUtil.isAncestor(myField, element, false)) - { - conflicts.putValue(element, "Inlined method is used in javadoc"); - } - } - } - } - - return showConflicts(conflicts, usagesIn); - } - - private static boolean isAccessedForWriting(PsiExpression expr) - { - while (expr.getParent() instanceof PsiArrayAccessExpression) - { - expr = (PsiExpression) expr.getParent(); - } - - return PsiUtil.isAccessedForWriting(expr); - } - - @Override - @Nonnull - protected Collection getElementsToWrite(@Nonnull final UsageViewDescriptor descriptor) - { - if (myInlineThisOnly) - { - return Collections.singletonList(myRefExpr); - } - else - { - return super.getElementsToWrite(descriptor); - } - } +public class InlineConstantFieldProcessor extends BaseRefactoringProcessor { + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.inline" + + ".InlineConstantFieldProcessor"); + private PsiField myField; + private final PsiReferenceExpression myRefExpr; + private final boolean myInlineThisOnly; + private final boolean mySearchInCommentsAndStrings; + private final boolean mySearchForTextOccurrences; + + public InlineConstantFieldProcessor( + PsiField field, + Project project, + PsiReferenceExpression ref, + boolean isInlineThisOnly + ) { + this(field, project, ref, isInlineThisOnly, false, false); + } + + public InlineConstantFieldProcessor( + PsiField field, + Project project, + PsiReferenceExpression ref, + boolean isInlineThisOnly, + boolean searchInCommentsAndStrings, + boolean searchForTextOccurrences + ) { + super(project); + myField = field; + myRefExpr = ref; + myInlineThisOnly = isInlineThisOnly; + mySearchInCommentsAndStrings = searchInCommentsAndStrings; + mySearchForTextOccurrences = searchForTextOccurrences; + } + + @Override + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new InlineViewDescriptor(myField); + } + + @Override + protected boolean isPreviewUsages(@Nonnull UsageInfo[] usages) { + if (super.isPreviewUsages(usages)) { + return true; + } + for (UsageInfo info : usages) { + if (info instanceof NonCodeUsageInfo) { + return true; + } + } + return false; + } + + private static class UsageFromJavaDoc extends UsageInfo { + private UsageFromJavaDoc(@Nonnull PsiElement element) { + super(element, true); + } + } + + @Nonnull + @Override + @RequiredUIAccess + protected UsageInfo[] findUsages() { + if (myInlineThisOnly) { + return new UsageInfo[]{new UsageInfo(myRefExpr)}; + } + + List usages = new ArrayList<>(); + for (PsiReference ref : ReferencesSearch.search(myField, GlobalSearchScope.projectScope(myProject), false)) { + PsiElement element = ref.getElement(); + UsageInfo info = new UsageInfo(element); + + if (!(element instanceof PsiExpression) + && PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) == null) { + info = new UsageFromJavaDoc(element); + } + + usages.add(info); + } + if (mySearchInCommentsAndStrings || mySearchForTextOccurrences) { + UsageInfoFactory nonCodeUsageFactory = new NonCodeUsageInfoFactory(myField, myField.getName()) { + @Override + public UsageInfo createUsageInfo(@Nonnull PsiElement usage, int startOffset, int endOffset) { + if (PsiTreeUtil.isAncestor(myField, usage, false)) { + return null; + } + return super.createUsageInfo(usage, startOffset, endOffset); + } + }; + if (mySearchInCommentsAndStrings) { + String stringToSearch = + ElementDescriptionUtil.getElementDescription(myField, NonCodeSearchDescriptionLocation.STRINGS_AND_COMMENTS); + TextOccurrencesUtil.addUsagesInStringsAndComments(myField, stringToSearch, usages, nonCodeUsageFactory); + } + + if (mySearchForTextOccurrences) { + String stringToSearch = + ElementDescriptionUtil.getElementDescription(myField, NonCodeSearchDescriptionLocation.NON_JAVA); + TextOccurrencesUtil.addTextOccurences( + myField, + stringToSearch, + GlobalSearchScope.projectScope(myProject), + usages, + nonCodeUsageFactory + ); + } + } + return usages.toArray(new UsageInfo[usages.size()]); + } + + @Override + protected void refreshElements(@Nonnull PsiElement[] elements) { + LOG.assertTrue(elements.length == 1 && elements[0] instanceof PsiField); + myField = (PsiField)elements[0]; + } + + @Override + @RequiredUIAccess + protected void performRefactoring(@Nonnull UsageInfo[] usages) { + PsiExpression initializer = myField.getInitializer(); + LOG.assertTrue(initializer != null); + + initializer = normalize((PsiExpression)initializer.copy()); + for (UsageInfo info : usages) { + if (info instanceof UsageFromJavaDoc) { + continue; + } + if (info instanceof NonCodeUsageInfo) { + continue; + } + PsiElement element = info.getElement(); + if (element == null) { + continue; + } + try { + if (element instanceof PsiExpression expression) { + inlineExpressionUsage(expression, initializer); + } + else { + PsiImportStaticStatement importStaticStatement = + PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class); + LOG.assertTrue(importStaticStatement != null, element.getText()); + importStaticStatement.delete(); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + + if (!myInlineThisOnly) { + try { + myField.delete(); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + + /* + @Nullable + @Override + protected RefactoringEventData getBeforeData() + { + RefactoringEventData data = new RefactoringEventData(); + data.addElement(myField); + return data; + } + + @Nullable + @Override + protected String getRefactoringId() + { + return "refactoring.inline.field"; + } + */ + + private void inlineExpressionUsage(PsiExpression expr, PsiExpression initializer1) throws IncorrectOperationException { + if (myField.isWritable()) { + myField.normalizeDeclaration(); + } + if (expr instanceof PsiReferenceExpression refExpr) { + PsiExpression qExpression = refExpr.getQualifierExpression(); + if (qExpression != null) { + PsiReferenceExpression initRefExpr = null; + if (initializer1 instanceof PsiReferenceExpression initRefExpr1) { + initRefExpr = initRefExpr1; + } + else if (initializer1 instanceof PsiMethodCallExpression methodCall) { + initRefExpr = methodCall.getMethodExpression(); + } + if (initRefExpr != null && initRefExpr.getQualifierExpression() == null + && !(initRefExpr.advancedResolve(false).getCurrentFileResolveScope() instanceof PsiImportStaticStatement)) { + initRefExpr.setQualifierExpression(qExpression); + } + } + } + + InlineUtil.inlineVariable(myField, initializer1, (PsiJavaCodeReferenceElement)expr); + } + + private static PsiExpression normalize(PsiExpression expression) { + if (expression instanceof PsiArrayInitializerExpression) { + PsiElementFactory factory = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory(); + try { + PsiType type = expression.getType(); + if (type != null) { + String typeString = type.getCanonicalText(); + PsiNewExpression result = + (PsiNewExpression)factory.createExpressionFromText("new " + typeString + "{}", expression); + result.getArrayInitializer().replace(expression); + return result; + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + return expression; + } + } + + return expression; + } + + @Nonnull + @Override + @RequiredReadAction + protected String getCommandName() { + return RefactoringLocalize.inlineFieldCommand(DescriptiveNameUtil.getDescriptiveName(myField)).get(); + } + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + UsageInfo[] usagesIn = refUsages.get(); + MultiMap conflicts = new MultiMap<>(); + + ReferencedElementsCollector collector = new ReferencedElementsCollector(); + PsiExpression initializer = myField.getInitializer(); + LOG.assertTrue(initializer != null); + initializer.accept(collector); + HashSet referencedWithVisibility = collector.myReferencedMembers; + + PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myField.getProject()).getResolveHelper(); + for (UsageInfo info : usagesIn) { + PsiElement element = info.getElement(); + if (element instanceof PsiExpression expression && isAccessedForWriting(expression)) { + LocalizeValue message = RefactoringLocalize.zeroIsUsedForWritingIn1( + RefactoringUIUtil.getDescription(myField, true), + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true) + ); + conflicts.putValue(element, message.get()); + } + + for (PsiMember member : referencedWithVisibility) { + if (!resolveHelper.isAccessible(member, element, null)) { + LocalizeValue message = RefactoringLocalize.zeroWillNotBeAccessibleFrom1AfterInlining( + RefactoringUIUtil.getDescription(member, true), + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true) + ); + conflicts.putValue(member, message.get()); + } + } + } + + if (!myInlineThisOnly) { + for (UsageInfo info : usagesIn) { + if (info instanceof UsageFromJavaDoc) { + PsiElement element = info.getElement(); + if (element instanceof PsiDocMethodOrFieldRef && !PsiTreeUtil.isAncestor(myField, element, false)) { + conflicts.putValue(element, "Inlined method is used in javadoc"); + } + } + } + } + + return showConflicts(conflicts, usagesIn); + } + + private static boolean isAccessedForWriting(PsiExpression expr) { + while (expr.getParent() instanceof PsiArrayAccessExpression arrayAccess) { + expr = arrayAccess; + } + + return PsiUtil.isAccessedForWriting(expr); + } + + @Override + @Nonnull + protected Collection getElementsToWrite(@Nonnull UsageViewDescriptor descriptor) { + if (myInlineThisOnly) { + return Collections.singletonList(myRefExpr); + } + else { + return super.getElementsToWrite(descriptor); + } + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineParameterExpressionProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineParameterExpressionProcessor.java index eab4b9473..4052e9e80 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineParameterExpressionProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineParameterExpressionProcessor.java @@ -22,6 +22,8 @@ import com.intellij.java.language.impl.codeInsight.ExceptionUtil; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.editor.refactoring.ui.RefactoringUIUtil; import consulo.language.psi.PsiElement; @@ -30,382 +32,407 @@ import consulo.language.psi.search.ReferencesSearch; import consulo.language.psi.util.PsiTreeUtil; import consulo.logging.Logger; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.usage.UsageViewUtil; import consulo.util.collection.MultiMap; import consulo.util.dataholder.Key; -import consulo.util.lang.ref.Ref; - +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.util.*; /** * @author yole */ public class InlineParameterExpressionProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(InlineParameterExpressionProcessor.class); - public static final Key CREATE_LOCAL_FOR_TESTS = Key.create("CREATE_INLINE_PARAMETER_LOCAL_FOR_TESTS"); - - private final PsiCallExpression myMethodCall; - private final PsiMethod myMethod; - private final PsiParameter myParameter; - private PsiExpression myInitializer; - private final boolean mySameClass; - private final PsiMethod myCallingMethod; - private final boolean myCreateLocal; - - public InlineParameterExpressionProcessor(final PsiCallExpression methodCall, - final PsiMethod method, - final PsiParameter parameter, - final PsiExpression initializer, - boolean createLocal) { - super(method.getProject()); - myMethodCall = methodCall; - myMethod = method; - myParameter = parameter; - myInitializer = initializer; - myCreateLocal = createLocal; - - PsiClass callingClass = PsiTreeUtil.getParentOfType(methodCall, PsiClass.class); - mySameClass = (callingClass == myMethod.getContainingClass()); - myCallingMethod = PsiTreeUtil.getParentOfType(myMethodCall, PsiMethod.class); - } - - @Override - protected String getCommandName() { - return InlineParameterHandler.REFACTORING_NAME; - } - - - @Nonnull - @Override - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new InlineViewDescriptor(myParameter); - } - - @Nonnull - @Override - protected UsageInfo[] findUsages() { - - int parameterIndex = myMethod.getParameterList().getParameterIndex(myParameter); - final Map localToParamRef = new HashMap(); - final PsiExpression[] arguments = myMethodCall.getArgumentList().getExpressions(); - for (int i = 0; i < arguments.length; i++) { - if (i != parameterIndex && arguments[i] instanceof PsiReferenceExpression) { - final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) arguments[i]; - final PsiElement element = referenceExpression.resolve(); - if (element instanceof PsiLocalVariable || element instanceof PsiParameter) { - final PsiParameter param = myMethod.getParameterList().getParameters()[i]; - final PsiExpression paramRef = - JavaPsiFacade.getInstance(myMethod.getProject()).getElementFactory().createExpressionFromText(param.getName(), myMethod); - localToParamRef.put((PsiVariable) element, paramRef); - } - } + private static final Logger LOG = Logger.getInstance(InlineParameterExpressionProcessor.class); + public static final Key CREATE_LOCAL_FOR_TESTS = Key.create("CREATE_INLINE_PARAMETER_LOCAL_FOR_TESTS"); + + private final PsiCallExpression myMethodCall; + private final PsiMethod myMethod; + private final PsiParameter myParameter; + private PsiExpression myInitializer; + private final boolean mySameClass; + private final PsiMethod myCallingMethod; + private final boolean myCreateLocal; + + public InlineParameterExpressionProcessor( + PsiCallExpression methodCall, + PsiMethod method, + PsiParameter parameter, + PsiExpression initializer, + boolean createLocal + ) { + super(method.getProject()); + myMethodCall = methodCall; + myMethod = method; + myParameter = parameter; + myInitializer = initializer; + myCreateLocal = createLocal; + + PsiClass callingClass = PsiTreeUtil.getParentOfType(methodCall, PsiClass.class); + mySameClass = (callingClass == myMethod.getContainingClass()); + myCallingMethod = PsiTreeUtil.getParentOfType(myMethodCall, PsiMethod.class); } - final List result = new ArrayList(); - myInitializer.accept(new JavaRecursiveElementVisitor() { - @Override - public void visitReferenceExpression(final PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement element = expression.resolve(); - if (element instanceof PsiLocalVariable) { - final PsiLocalVariable localVariable = (PsiLocalVariable) element; - final PsiElement[] elements = DefUseUtil.getDefs(myCallingMethod.getBody(), localVariable, expression); - if (elements.length == 1) { - PsiExpression localInitializer = null; - if (elements[0] instanceof PsiLocalVariable) { - localInitializer = ((PsiLocalVariable) elements[0]).getInitializer(); - } else if (elements[0] instanceof PsiAssignmentExpression) { - localInitializer = ((PsiAssignmentExpression) elements[0]).getRExpression(); - } else if (elements[0] instanceof PsiReferenceExpression) { - final PsiReferenceExpression refElement = (PsiReferenceExpression) elements[0]; - final PsiElement parent = refElement.getParent(); - if (parent instanceof PsiAssignmentExpression && ((PsiAssignmentExpression) parent).getLExpression() == refElement) { - localInitializer = ((PsiAssignmentExpression) parent).getRExpression(); - } - } - if (localInitializer != null) { - final PsiElement replacement; - if (localToParamRef.containsKey(localVariable)) { - replacement = localToParamRef.get(localVariable); - } else { - replacement = replaceArgs(localToParamRef, localInitializer.copy()); - } - result.add(new LocalReplacementUsageInfo(expression, replacement)); - } - } - } - } - }); + @Nonnull + @Override + protected String getCommandName() { + return InlineParameterHandler.REFACTORING_NAME; + } - if (!myCreateLocal) { - for (PsiReference ref : ReferencesSearch.search(myParameter).findAll()) { - result.add(new UsageInfo(ref)); - } + @Nonnull + @Override + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new InlineViewDescriptor(myParameter); } - final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); - return UsageViewUtil.removeDuplicatedUsages(usageInfos); - } - - private static PsiElement replaceArgs(final Map elementsToReplace, PsiElement expression) { - final Map replacements = new HashMap(); - expression.accept(new JavaRecursiveElementVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression referenceExpression) { - super.visitReferenceExpression(referenceExpression); - final PsiElement resolved = referenceExpression.resolve(); - if (resolved instanceof PsiVariable) { - final PsiVariable variable = (PsiVariable) resolved; - final PsiElement replacement = elementsToReplace.get(variable); - if (replacement != null) { - replacements.put(referenceExpression, replacement); - } + @Nonnull + @Override + @RequiredReadAction + protected UsageInfo[] findUsages() { + int parameterIndex = myMethod.getParameterList().getParameterIndex(myParameter); + Map localToParamRef = new HashMap<>(); + PsiExpression[] arguments = myMethodCall.getArgumentList().getExpressions(); + for (int i = 0; i < arguments.length; i++) { + if (i != parameterIndex && arguments[i] instanceof PsiReferenceExpression refExpr) { + PsiElement element = refExpr.resolve(); + if (element instanceof PsiLocalVariable || element instanceof PsiParameter) { + PsiParameter param = myMethod.getParameterList().getParameters()[i]; + PsiExpression paramRef = JavaPsiFacade.getInstance(myMethod.getProject()) + .getElementFactory() + .createExpressionFromText(param.getName(), myMethod); + localToParamRef.put((PsiVariable)element, paramRef); + } + } } - } - }); - return RefactoringUtil.replaceElementsWithMap(expression, replacements); - } - - @Override - protected boolean preprocessUsages(Ref refUsages) { - final MultiMap conflicts = new MultiMap(); - final UsageInfo[] usages = refUsages.get(); - final InaccessibleExpressionsDetector detector = new InaccessibleExpressionsDetector(conflicts); - myInitializer.accept(detector); - for (UsageInfo usage : usages) { - if (usage instanceof LocalReplacementUsageInfo) { - final PsiElement replacement = ((LocalReplacementUsageInfo) usage).getReplacement(); - if (replacement != null) { - replacement.accept(detector); + + List result = new ArrayList<>(); + myInitializer.accept(new JavaRecursiveElementVisitor() { + @RequiredWriteAction + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (expression.resolve() instanceof PsiLocalVariable localVariable) { + PsiElement[] elements = DefUseUtil.getDefs(myCallingMethod.getBody(), localVariable, expression); + if (elements.length == 1) { + PsiExpression localInitializer = null; + if (elements[0] instanceof PsiLocalVariable localVar) { + localInitializer = localVar.getInitializer(); + } + else if (elements[0] instanceof PsiAssignmentExpression assignment) { + localInitializer = assignment.getRExpression(); + } + else if (elements[0] instanceof PsiReferenceExpression refElement) { + if (refElement.getParent() instanceof PsiAssignmentExpression assignment + && assignment.getLExpression() == refElement) { + localInitializer = assignment.getRExpression(); + } + } + if (localInitializer != null) { + PsiElement replacement; + if (localToParamRef.containsKey(localVariable)) { + replacement = localToParamRef.get(localVariable); + } + else { + replacement = replaceArgs(localToParamRef, localInitializer.copy()); + } + result.add(new LocalReplacementUsageInfo(expression, replacement)); + } + } + } + } + }); + + if (!myCreateLocal) { + for (PsiReference ref : ReferencesSearch.search(myParameter).findAll()) { + result.add(new UsageInfo(ref)); + } } - } + + UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); + return UsageViewUtil.removeDuplicatedUsages(usageInfos); } - final Set vars = new HashSet(); - for (UsageInfo usageInfo : usages) { - if (usageInfo instanceof LocalReplacementUsageInfo) { - final PsiVariable var = ((LocalReplacementUsageInfo) usageInfo).getVariable(); - if (var != null) { - vars.add(var); - } - } + @RequiredWriteAction + private static PsiElement replaceArgs(Map elementsToReplace, PsiElement expression) { + Map replacements = new HashMap<>(); + expression.accept(new JavaRecursiveElementVisitor() { + @Override + @RequiredReadAction + public void visitReferenceExpression(PsiReferenceExpression referenceExpression) { + super.visitReferenceExpression(referenceExpression); + if (referenceExpression.resolve() instanceof PsiVariable variable) { + PsiElement replacement = elementsToReplace.get(variable); + if (replacement != null) { + replacements.put(referenceExpression, replacement); + } + } + } + }); + return RefactoringUtil.replaceElementsWithMap(expression, replacements); } - for (PsiVariable var : vars) { - for (PsiReference ref : ReferencesSearch.search(var)) { - final PsiElement element = ref.getElement(); - if (element instanceof PsiExpression && isAccessedForWriting((PsiExpression) element)) { - conflicts.putValue(element, "Parameter initializer depends on value which is not available inside method and cannot be inlined"); - break; + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(SimpleReference refUsages) { + MultiMap conflicts = new MultiMap<>(); + UsageInfo[] usages = refUsages.get(); + InaccessibleExpressionsDetector detector = new InaccessibleExpressionsDetector(conflicts); + myInitializer.accept(detector); + for (UsageInfo usage : usages) { + if (usage instanceof LocalReplacementUsageInfo localReplacementUsageInfo) { + PsiElement replacement = localReplacementUsageInfo.getReplacement(); + if (replacement != null) { + replacement.accept(detector); + } + } } - } - } - return showConflicts(conflicts, usages); - } - private static boolean isAccessedForWriting(PsiExpression expr) { - while (expr.getParent() instanceof PsiArrayAccessExpression) { - expr = (PsiExpression) expr.getParent(); - } - return PsiUtil.isAccessedForWriting(expr); - } - - @Override - protected void performRefactoring(UsageInfo[] usages) { - final List thrownExceptions = ExceptionUtil.getThrownCheckedExceptions(new PsiElement[]{myInitializer}); - final Set varsUsedInInitializer = new HashSet(); - final Set paramRefsToInline = new HashSet(); - final Map replacements = new HashMap(); - for (UsageInfo usage : usages) { - if (usage instanceof LocalReplacementUsageInfo) { - final LocalReplacementUsageInfo replacementUsageInfo = (LocalReplacementUsageInfo) usage; - final PsiElement element = replacementUsageInfo.getElement(); - final PsiElement replacement = replacementUsageInfo.getReplacement(); - if (element != null && replacement != null) { - replacements.put(element, replacement); + Set vars = new HashSet<>(); + for (UsageInfo usageInfo : usages) { + if (usageInfo instanceof LocalReplacementUsageInfo localReplacementUsageInfo) { + PsiVariable var = localReplacementUsageInfo.getVariable(); + if (var != null) { + vars.add(var); + } + } } - varsUsedInInitializer.add(replacementUsageInfo.getVariable()); - } else { - LOG.assertTrue(!myCreateLocal); - paramRefsToInline.add((PsiJavaCodeReferenceElement) usage.getElement()); - } - } - myInitializer = (PsiExpression) RefactoringUtil.replaceElementsWithMap(myInitializer, replacements); - - if (myCreateLocal) { - final PsiElementFactory factory = JavaPsiFacade.getInstance(myMethod.getProject()).getElementFactory(); - PsiDeclarationStatement localDeclaration = - factory.createVariableDeclarationStatement(myParameter.getName(), myParameter.getType(), myInitializer); - final PsiLocalVariable declaredVar = (PsiLocalVariable) localDeclaration.getDeclaredElements()[0]; - PsiUtil.setModifierProperty(declaredVar, PsiModifier.FINAL, myParameter.hasModifierProperty(PsiModifier.FINAL)); - final PsiExpression localVarInitializer = - InlineUtil.inlineVariable(myParameter, myInitializer, (PsiReferenceExpression) factory.createExpressionFromText(myParameter.getName(), myMethod)); - final PsiExpression initializer = declaredVar.getInitializer(); - LOG.assertTrue(initializer != null); - initializer.replace(localVarInitializer); - final PsiCodeBlock body = myMethod.getBody(); - if (body != null) { - PsiElement anchor = findAnchorForLocalVariableDeclaration(body); - body.addAfter(localDeclaration, anchor); - } - } else { - for (PsiJavaCodeReferenceElement paramRef : paramRefsToInline) { - InlineUtil.inlineVariable(myParameter, myInitializer, paramRef); - } + for (PsiVariable var : vars) { + for (PsiReference ref : ReferencesSearch.search(var)) { + if (ref.getElement() instanceof PsiExpression expression && isAccessedForWriting(expression)) { + conflicts.putValue( + expression, + "Parameter initializer depends on value which is not available inside method and cannot be inlined" + ); + break; + } + } + } + return showConflicts(conflicts, usages); } - //delete var if it becomes unused - for (PsiVariable variable : varsUsedInInitializer) { - if (variable != null && variable.isValid()) { - if (ReferencesSearch.search(variable).findFirst() == null) { - variable.delete(); + private static boolean isAccessedForWriting(PsiExpression expr) { + while (expr.getParent() instanceof PsiArrayAccessExpression arrayAccessExpr) { + expr = arrayAccessExpr; } - } + return PsiUtil.isAccessedForWriting(expr); } - SameParameterValueInspection.InlineParameterValueFix.removeParameter(myMethod, myParameter); - - if (!thrownExceptions.isEmpty()) { - for (PsiClassType exception : thrownExceptions) { - PsiClass exceptionClass = exception.resolve(); - if (exceptionClass != null) { - PsiUtil.addException(myMethod, exceptionClass); + @Override + protected void performRefactoring(UsageInfo[] usages) { + List thrownExceptions = ExceptionUtil.getThrownCheckedExceptions(myInitializer); + Set varsUsedInInitializer = new HashSet<>(); + Set paramRefsToInline = new HashSet<>(); + Map replacements = new HashMap<>(); + for (UsageInfo usage : usages) { + if (usage instanceof LocalReplacementUsageInfo replacementUsageInfo) { + PsiElement element = replacementUsageInfo.getElement(); + PsiElement replacement = replacementUsageInfo.getReplacement(); + if (element != null && replacement != null) { + replacements.put(element, replacement); + } + varsUsedInInitializer.add(replacementUsageInfo.getVariable()); + } + else { + LOG.assertTrue(!myCreateLocal); + paramRefsToInline.add((PsiJavaCodeReferenceElement)usage.getElement()); + } } - } - } - } - - @Nullable - private PsiElement findAnchorForLocalVariableDeclaration(PsiCodeBlock body) { - PsiElement anchor = body.getLBrace(); - if (myMethod.isConstructor()) { - final PsiStatement[] statements = body.getStatements(); - if (statements.length > 0 && statements[0] instanceof PsiExpressionStatement) { - final PsiExpression expression = ((PsiExpressionStatement) statements[0]).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - final String referenceName = ((PsiMethodCallExpression) expression).getMethodExpression().getReferenceName(); - if (PsiKeyword.SUPER.equals(referenceName) || PsiKeyword.THIS.equals(referenceName)) { - anchor = statements[0]; - } + myInitializer = (PsiExpression)RefactoringUtil.replaceElementsWithMap(myInitializer, replacements); + + if (myCreateLocal) { + PsiElementFactory factory = JavaPsiFacade.getInstance(myMethod.getProject()).getElementFactory(); + PsiDeclarationStatement localDeclaration = + factory.createVariableDeclarationStatement(myParameter.getName(), myParameter.getType(), myInitializer); + PsiLocalVariable declaredVar = (PsiLocalVariable)localDeclaration.getDeclaredElements()[0]; + PsiUtil.setModifierProperty(declaredVar, PsiModifier.FINAL, myParameter.hasModifierProperty(PsiModifier.FINAL)); + PsiExpression localVarInitializer = InlineUtil.inlineVariable( + myParameter, + myInitializer, + (PsiReferenceExpression)factory.createExpressionFromText(myParameter.getName(), myMethod) + ); + PsiExpression initializer = declaredVar.getInitializer(); + LOG.assertTrue(initializer != null); + initializer.replace(localVarInitializer); + PsiCodeBlock body = myMethod.getBody(); + if (body != null) { + PsiElement anchor = findAnchorForLocalVariableDeclaration(body); + body.addAfter(localDeclaration, anchor); + } + } + else { + for (PsiJavaCodeReferenceElement paramRef : paramRefsToInline) { + InlineUtil.inlineVariable(myParameter, myInitializer, paramRef); + } } - } - } - return anchor; - } - - private static class LocalReplacementUsageInfo extends UsageInfo { - private final PsiElement myReplacement; - private final PsiVariable myVariable; - - public LocalReplacementUsageInfo(@Nonnull PsiReference element, @Nonnull PsiElement replacement) { - super(element); - final PsiElement resolved = element.resolve(); - myVariable = resolved instanceof PsiVariable ? (PsiVariable) resolved : null; - myReplacement = replacement; - } - @Nullable - public PsiElement getReplacement() { - return myReplacement.isValid() ? myReplacement : null; + //delete var if it becomes unused + for (PsiVariable variable : varsUsedInInitializer) { + if (variable != null && variable.isValid()) { + if (ReferencesSearch.search(variable).findFirst() == null) { + variable.delete(); + } + } + } + + SameParameterValueInspection.InlineParameterValueFix.removeParameter(myMethod, myParameter); + + if (!thrownExceptions.isEmpty()) { + for (PsiClassType exception : thrownExceptions) { + PsiClass exceptionClass = exception.resolve(); + if (exceptionClass != null) { + PsiUtil.addException(myMethod, exceptionClass); + } + } + } } @Nullable - public PsiVariable getVariable() { - return myVariable != null && myVariable.isValid() ? myVariable : null; + private PsiElement findAnchorForLocalVariableDeclaration(PsiCodeBlock body) { + PsiElement anchor = body.getLBrace(); + if (myMethod.isConstructor()) { + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0 && statements[0] instanceof PsiExpressionStatement exprStmt + && exprStmt.getExpression() instanceof PsiMethodCallExpression methodCall) { + String referenceName = methodCall.getMethodExpression().getReferenceName(); + if (PsiKeyword.SUPER.equals(referenceName) || PsiKeyword.THIS.equals(referenceName)) { + anchor = exprStmt; + } + } + } + return anchor; } - } - private class InaccessibleExpressionsDetector extends JavaRecursiveElementWalkingVisitor { - private final MultiMap myConflicts; + private static class LocalReplacementUsageInfo extends UsageInfo { + private final PsiElement myReplacement; + private final PsiVariable myVariable; - public InaccessibleExpressionsDetector(MultiMap conflicts) { - myConflicts = conflicts; - } + @RequiredReadAction + public LocalReplacementUsageInfo(@Nonnull PsiReference element, @Nonnull PsiElement replacement) { + super(element); + myVariable = element.resolve() instanceof PsiVariable variable ? variable : null; + myReplacement = replacement; + } - @Override - public void visitReferenceExpression(final PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement element = expression.resolve(); - if (element instanceof PsiMember && !((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC)) { - if (myMethod.hasModifierProperty(PsiModifier.STATIC)) { - myConflicts.putValue(expression, "Parameter initializer depends on " + RefactoringUIUtil.getDescription(element, false) + " which is not available inside the static method"); + @Nullable + public PsiElement getReplacement() { + return myReplacement.isValid() ? myReplacement : null; } - } - if (element instanceof PsiMethod || element instanceof PsiField) { - if (!mySameClass && !((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC)) { - myConflicts.putValue(expression, "Parameter initializer depends on non static member from some other class"); - } else if (!PsiUtil.isAccessible((PsiMember) element, myMethod, null)) { - myConflicts.putValue(expression, "Parameter initializer depends on value which is not available inside method"); + + @Nullable + public PsiVariable getVariable() { + return myVariable != null && myVariable.isValid() ? myVariable : null; } - } else if (element instanceof PsiParameter) { - myConflicts.putValue(expression, "Parameter initializer depends on callers parameter"); - } } - @Override - public void visitThisExpression(PsiThisExpression thisExpression) { - super.visitThisExpression(thisExpression); - final PsiJavaCodeReferenceElement qualifier = thisExpression.getQualifier(); - PsiElement containingClass; - if (qualifier != null) { - containingClass = qualifier.resolve(); - } else { - containingClass = PsiTreeUtil.getParentOfType(myMethodCall, PsiClass.class); - } - final PsiClass methodContainingClass = myMethod.getContainingClass(); - LOG.assertTrue(methodContainingClass != null); - if (!PsiTreeUtil.isAncestor(containingClass, methodContainingClass, false)) { - myConflicts.putValue(thisExpression, - "Parameter initializer depends on this which is not available inside the method and cannot be inlined"); - } else if (myMethod.hasModifierProperty(PsiModifier.STATIC)) { - myConflicts.putValue(thisExpression, "Parameter initializer depends on this which is not available inside the static method"); - } - } + private class InaccessibleExpressionsDetector extends JavaRecursiveElementWalkingVisitor { + private final MultiMap myConflicts; - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - super.visitReferenceElement(reference); - if (myMethod.hasModifierProperty(PsiModifier.STATIC)) { - final PsiElement resolved = reference.resolve(); - if (resolved instanceof PsiClass && !((PsiClass) resolved).hasModifierProperty(PsiModifier.STATIC)) { - myConflicts.putValue(reference, "Parameter initializer depends on non static class which is not available inside static method"); + public InaccessibleExpressionsDetector(MultiMap conflicts) { + myConflicts = conflicts; } - } - } - @Override - public void visitNewExpression(PsiNewExpression expression) { - super.visitNewExpression(expression); - final PsiJavaCodeReferenceElement reference = expression.getClassOrAnonymousClassReference(); - if (reference != null) { - final PsiElement resolved = reference.resolve(); - if (resolved instanceof PsiClass) { - final PsiClass refClass = (PsiClass) resolved; - final String classUnavailableMessage = "Parameter initializer depends on " + - RefactoringUIUtil.getDescription(refClass, true) + - " which is not available inside method and cannot be inlined"; - if (!PsiUtil.isAccessible(refClass, myMethod, null)) { - myConflicts.putValue(expression, classUnavailableMessage); - } else { - final PsiClass methodContainingClass = myMethod.getContainingClass(); + @Override + @RequiredReadAction + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + PsiElement element = expression.resolve(); + if (element instanceof PsiMember member && !member.isStatic()) { + if (myMethod.isStatic()) { + myConflicts.putValue( + expression, + "Parameter initializer depends on " + RefactoringUIUtil.getDescription( + element, + false + ) + " which is not available inside the static method" + ); + } + } + if (element instanceof PsiMethod || element instanceof PsiField) { + if (!mySameClass && !((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.STATIC)) { + myConflicts.putValue(expression, "Parameter initializer depends on non static member from some other class"); + } + else if (!PsiUtil.isAccessible((PsiMember)element, myMethod, null)) { + myConflicts.putValue(expression, "Parameter initializer depends on value which is not available inside method"); + } + } + else if (element instanceof PsiParameter) { + myConflicts.putValue(expression, "Parameter initializer depends on callers parameter"); + } + } + + @Override + @RequiredReadAction + public void visitThisExpression(@Nonnull PsiThisExpression thisExpression) { + super.visitThisExpression(thisExpression); + PsiJavaCodeReferenceElement qualifier = thisExpression.getQualifier(); + PsiElement containingClass; + if (qualifier != null) { + containingClass = qualifier.resolve(); + } + else { + containingClass = PsiTreeUtil.getParentOfType(myMethodCall, PsiClass.class); + } + PsiClass methodContainingClass = myMethod.getContainingClass(); LOG.assertTrue(methodContainingClass != null); - if (!PsiTreeUtil.isAncestor(myMethod, refClass, false)) { - PsiElement parent = refClass; - while ((parent = parent.getParent()) instanceof PsiClass) { - if (!PsiUtil.isAccessible((PsiClass) parent, myMethod, null)) { - break; + if (!PsiTreeUtil.isAncestor(containingClass, methodContainingClass, false)) { + myConflicts.putValue( + thisExpression, + "Parameter initializer depends on this which is not available inside the method and cannot be inlined" + ); + } + else if (myMethod.isStatic()) { + myConflicts.putValue( + thisExpression, + "Parameter initializer depends on this which is not available inside the static method" + ); + } + } + + @Override + @RequiredReadAction + public void visitReferenceElement(@Nonnull PsiJavaCodeReferenceElement reference) { + super.visitReferenceElement(reference); + if (myMethod.isStatic() && reference.resolve() instanceof PsiClass psiClass && !psiClass.isStatic()) { + myConflicts.putValue( + reference, + "Parameter initializer depends on non static class which is not available inside static method" + ); + } + } + + @Override + @RequiredReadAction + public void visitNewExpression(@Nonnull PsiNewExpression expression) { + super.visitNewExpression(expression); + PsiJavaCodeReferenceElement reference = expression.getClassOrAnonymousClassReference(); + if (reference != null && reference.resolve() instanceof PsiClass refClass) { + String classUnavailableMessage = "Parameter initializer depends on " + + RefactoringUIUtil.getDescription(refClass, true) + + " which is not available inside method and cannot be inlined"; + if (!PsiUtil.isAccessible(refClass, myMethod, null)) { + myConflicts.putValue(expression, classUnavailableMessage); + } + else { + PsiClass methodContainingClass = myMethod.getContainingClass(); + LOG.assertTrue(methodContainingClass != null); + if (!PsiTreeUtil.isAncestor(myMethod, refClass, false)) { + PsiElement parent = refClass; + while ((parent = parent.getParent()) instanceof PsiClass psiClass) { + if (!PsiUtil.isAccessible(psiClass, myMethod, null)) { + break; + } + } + if (!(parent instanceof PsiFile)) { + myConflicts.putValue(expression, classUnavailableMessage); + } + } } - } - if (!(parent instanceof PsiFile)) { - myConflicts.putValue(expression, classUnavailableMessage); - } } - } } - } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java index acbc93c4e..75d2b1a7f 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java @@ -33,7 +33,6 @@ import com.intellij.java.language.psi.util.TypeConversionUtil; import consulo.annotation.access.RequiredReadAction; import consulo.ide.impl.idea.refactoring.util.DocCommentPolicy; -import consulo.ide.impl.idea.util.ArrayUtilRt; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; import consulo.language.psi.PsiElement; import consulo.language.psi.PsiReference; @@ -45,8 +44,9 @@ import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; +import consulo.util.collection.ArrayUtil; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -55,345 +55,362 @@ import java.util.Map; public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactoringProcessor { - public static final Logger LOG = Logger.getInstance(InlineSuperClassRefactoringProcessor.class); + public static final Logger LOG = Logger.getInstance(InlineSuperClassRefactoringProcessor.class); - private final PsiClass myCurrentInheritor; - private final PsiClass mySuperClass; - private final int myPolicy; - private final PsiClass[] myTargetClasses; - private final MemberInfo[] myMemberInfos; + private final PsiClass myCurrentInheritor; + private final PsiClass mySuperClass; + private final int myPolicy; + private final PsiClass[] myTargetClasses; + private final MemberInfo[] myMemberInfos; - public InlineSuperClassRefactoringProcessor( - Project project, - PsiClass currentInheritor, - PsiClass superClass, - int policy, - final PsiClass... targetClasses - ) { - super(project); - myCurrentInheritor = currentInheritor; - mySuperClass = superClass; - myPolicy = policy; - myTargetClasses = currentInheritor != null ? new PsiClass[]{currentInheritor} : targetClasses; - MemberInfoStorage memberInfoStorage = new MemberInfoStorage(mySuperClass, new MemberInfo.Filter() { - public boolean includeMember(PsiMember element) { - return !(element instanceof PsiClass) || PsiTreeUtil.isAncestor(mySuperClass, element, true); - } - }); - List members = memberInfoStorage.getClassMemberInfos(mySuperClass); - for (MemberInfo member : members) { - member.setChecked(true); + public InlineSuperClassRefactoringProcessor( + Project project, + PsiClass currentInheritor, + PsiClass superClass, + int policy, + PsiClass... targetClasses + ) { + super(project); + myCurrentInheritor = currentInheritor; + mySuperClass = superClass; + myPolicy = policy; + myTargetClasses = currentInheritor != null ? new PsiClass[]{currentInheritor} : targetClasses; + MemberInfoStorage memberInfoStorage = new MemberInfoStorage( + mySuperClass, + element -> !(element instanceof PsiClass psiClass && !PsiTreeUtil.isAncestor(mySuperClass, psiClass, true)) + ); + List members = memberInfoStorage.getClassMemberInfos(mySuperClass); + for (MemberInfo member : members) { + member.setChecked(true); + } + myMemberInfos = members.toArray(new MemberInfo[members.size()]); } - myMemberInfos = members.toArray(new MemberInfo[members.size()]); - } - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(final UsageInfo[] usages) { - return new InlineSuperClassUsageViewDescriptor(mySuperClass); - } + @Nonnull + @Override + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new InlineSuperClassUsageViewDescriptor(mySuperClass); + } - @RequiredReadAction - protected void findUsages(@Nonnull final List usages) { - final JavaPsiFacade facade = JavaPsiFacade.getInstance(myProject); - final PsiElementFactory elementFactory = facade.getElementFactory(); - final PsiResolveHelper resolveHelper = facade.getResolveHelper(); + @Override + @RequiredReadAction + protected void findUsages(@Nonnull List usages) { + JavaPsiFacade facade = JavaPsiFacade.getInstance(myProject); + PsiElementFactory elementFactory = facade.getElementFactory(); + PsiResolveHelper resolveHelper = facade.getResolveHelper(); - ReferencesSearch.search(mySuperClass).forEach(reference -> { - final PsiElement element = reference.getElement(); - if (element instanceof PsiJavaCodeReferenceElement) { - if (myCurrentInheritor != null) { - final PsiElement parent = element.getParent(); - if (parent instanceof PsiReferenceList) { - final PsiElement pparent = parent.getParent(); - if (pparent instanceof PsiClass) { - final PsiClass inheritor = (PsiClass) pparent; - if (parent.equals(inheritor.getExtendsList()) || parent.equals(inheritor.getImplementsList())) { - if (myCurrentInheritor.equals(inheritor)) { - usages.add(new ReplaceExtendsListUsageInfo((PsiJavaCodeReferenceElement) element, mySuperClass, inheritor)); + ReferencesSearch.search(mySuperClass).forEach(reference -> { + PsiElement element = reference.getElement(); + if (element instanceof PsiJavaCodeReferenceElement codeRef) { + if (myCurrentInheritor != null) { + if (element.getParent() instanceof PsiReferenceList refList + && refList.getParent() instanceof PsiClass inheritor + && (refList.equals(inheritor.getExtendsList()) || refList.equals(inheritor.getImplementsList())) + && myCurrentInheritor.equals(inheritor)) { + usages.add(new ReplaceExtendsListUsageInfo(codeRef, mySuperClass, inheritor)); + } + return true; + } + PsiImportStaticStatement staticImportStatement = PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class); + if (staticImportStatement != null) { + usages.add(new ReplaceStaticImportUsageInfo(staticImportStatement, myTargetClasses)); + } + else { + PsiImportStatement importStatement = PsiTreeUtil.getParentOfType(element, PsiImportStatement.class); + if (importStatement != null) { + usages.add(new RemoveImportUsageInfo(importStatement)); + } + else if (element.getParent() instanceof PsiReferenceList refList) { + if (refList.getParent() instanceof PsiClass inheritor + && (refList.equals(inheritor.getExtendsList()) || refList.equals(inheritor.getImplementsList()))) { + usages.add(new ReplaceExtendsListUsageInfo( + (PsiJavaCodeReferenceElement)element, + mySuperClass, + inheritor + )); + } + } + else { + PsiClass targetClass = myTargetClasses[0]; + PsiClassType targetClassType = elementFactory.createType( + targetClass, + TypeConversionUtil.getSuperClassSubstitutor(mySuperClass, targetClass, PsiSubstitutor.EMPTY) + ); + + if (element.getParent() instanceof PsiTypeElement typeElem) { + PsiType superClassType = typeElem.getType(); + PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass); + usages.add(new ReplaceWithSubtypeUsageInfo( + typeElem, + elementFactory.createType(targetClass, subst), + myTargetClasses + )); + } + else if (element.getParent() instanceof PsiNewExpression newExpr) { + PsiClassType newType = elementFactory.createType( + targetClass, + getSuperClassSubstitutor( + newExpr.getType(), + targetClassType, + resolveHelper, + targetClass + ) + ); + usages.add(new ReplaceConstructorUsageInfo(newExpr, newType, myTargetClasses)); + } + else if (element.getParent() instanceof PsiJavaCodeReferenceElement parentCodeRef) { + usages.add(new ReplaceReferenceUsageInfo(parentCodeRef.getQualifier(), myTargetClasses)); + } + } } - } } - } - return true; - } - final PsiImportStaticStatement staticImportStatement = PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class); - if (staticImportStatement != null) { - usages.add(new ReplaceStaticImportUsageInfo(staticImportStatement, myTargetClasses)); - } else { - final PsiImportStatement importStatement = PsiTreeUtil.getParentOfType(element, PsiImportStatement.class); - if (importStatement != null) { - usages.add(new RemoveImportUsageInfo(importStatement)); - } else { - final PsiElement parent = element.getParent(); - if (parent instanceof PsiReferenceList) { - final PsiElement pparent = parent.getParent(); - if (pparent instanceof PsiClass) { - final PsiClass inheritor = (PsiClass) pparent; - if (parent.equals(inheritor.getExtendsList()) || parent.equals(inheritor.getImplementsList())) { - usages.add(new ReplaceExtendsListUsageInfo((PsiJavaCodeReferenceElement) element, mySuperClass, inheritor)); + return true; + }); + for (PsiClass targetClass : myTargetClasses) { + for (MemberInfo memberInfo : myMemberInfos) { + PsiMember member = memberInfo.getMember(); + for (PsiReference reference : ReferencesSearch.search(member, member.getUseScope(), true)) { + if (reference.getElement() instanceof PsiReferenceExpression refExpr + && refExpr.getQualifierExpression() instanceof PsiSuperExpression + && PsiTreeUtil.isAncestor(targetClass, refExpr, false)) { + usages.add(new RemoveQualifierUsageInfo(refExpr)); + } } - } - } else { - final PsiClass targetClass = myTargetClasses[0]; - final PsiClassType targetClassType = elementFactory - .createType(targetClass, TypeConversionUtil.getSuperClassSubstitutor(mySuperClass, targetClass, PsiSubstitutor.EMPTY)); + } - if (parent instanceof PsiTypeElement) { - final PsiType superClassType = ((PsiTypeElement) parent).getType(); - PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass); - usages.add(new ReplaceWithSubtypeUsageInfo(((PsiTypeElement) parent), elementFactory.createType(targetClass, subst), myTargetClasses)); - } else if (parent instanceof PsiNewExpression) { - final PsiClassType newType = elementFactory.createType(targetClass, - getSuperClassSubstitutor(((PsiNewExpression) parent).getType(), - targetClassType, resolveHelper, - targetClass)); - usages.add(new ReplaceConstructorUsageInfo(((PsiNewExpression) parent), newType, myTargetClasses)); - } else if (parent instanceof PsiJavaCodeReferenceElement) { - usages.add(new ReplaceReferenceUsageInfo(((PsiJavaCodeReferenceElement) parent).getQualifier(), myTargetClasses)); - } + PsiMethod[] superConstructors = mySuperClass.getConstructors(); + for (PsiMethod constructor : targetClass.getConstructors()) { + PsiCodeBlock constrBody = constructor.getBody(); + LOG.assertTrue(constrBody != null); + PsiStatement[] statements = constrBody.getStatements(); + if (statements.length > 0 && statements[0] instanceof PsiExpressionStatement exprStmt + && exprStmt.getExpression() instanceof PsiMethodCallExpression methodCall + && methodCall.getMethodExpression().getText().equals(PsiKeyword.SUPER)) { + PsiMethod superConstructor = methodCall.resolveMethod(); + if (superConstructor != null && superConstructor.getBody() != null) { + usages.add(new InlineSuperCallUsageInfo(methodCall)); + continue; + } + } + + //insert implicit call to super + for (PsiMethod superConstructor : superConstructors) { + if (superConstructor.getParameterList().getParametersCount() == 0) { + PsiExpression expression = + JavaPsiFacade.getElementFactory(myProject).createExpressionFromText("super()", constructor); + usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression)expression, constrBody)); + } + } } - } - } - } - return true; - }); - for (PsiClass targetClass : myTargetClasses) { - for (MemberInfo memberInfo : myMemberInfos) { - final PsiMember member = memberInfo.getMember(); - for (PsiReference reference : ReferencesSearch.search(member, member.getUseScope(), true)) { - final PsiElement element = reference.getElement(); - if (element instanceof PsiReferenceExpression && - ((PsiReferenceExpression) element).getQualifierExpression() instanceof PsiSuperExpression && - PsiTreeUtil.isAncestor(targetClass, element, false)) { - usages.add(new RemoveQualifierUsageInfo((PsiReferenceExpression) element)); - } - } - } - final PsiMethod[] superConstructors = mySuperClass.getConstructors(); - for (PsiMethod constructor : targetClass.getConstructors()) { - final PsiCodeBlock constrBody = constructor.getBody(); - LOG.assertTrue(constrBody != null); - final PsiStatement[] statements = constrBody.getStatements(); - if (statements.length > 0) { - final PsiStatement firstConstrStatement = statements[0]; - if (firstConstrStatement instanceof PsiExpressionStatement) { - final PsiExpression expression = ((PsiExpressionStatement) firstConstrStatement).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) expression).getMethodExpression(); - if (methodExpression.getText().equals(PsiKeyword.SUPER)) { - final PsiMethod superConstructor = ((PsiMethodCallExpression) expression).resolveMethod(); - if (superConstructor != null && superConstructor.getBody() != null) { - usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression) expression)); - continue; + if (targetClass.getConstructors().length == 0) { + //copy default constructor + for (PsiMethod superConstructor : superConstructors) { + if (superConstructor.getParameterList().getParametersCount() == 0) { + usages.add(new CopyDefaultConstructorUsageInfo(targetClass, superConstructor)); + break; + } } - } } - } } + } - //insert implicit call to super - for (PsiMethod superConstructor : superConstructors) { - if (superConstructor.getParameterList().getParametersCount() == 0) { - final PsiExpression expression = JavaPsiFacade.getElementFactory(myProject).createExpressionFromText("super()", constructor); - usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression) expression, constrBody)); - } + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + MultiMap conflicts = new MultiMap<>(); + PushDownConflicts pushDownConflicts = new PushDownConflicts(mySuperClass, myMemberInfos); + for (PsiClass targetClass : myTargetClasses) { + for (MemberInfo info : myMemberInfos) { + PsiMember member = info.getMember(); + pushDownConflicts.checkMemberPlacementInTargetClassConflict(targetClass, member); + } + //todo check accessibility conflicts } - } - - if (targetClass.getConstructors().length == 0) { - //copy default constructor - for (PsiMethod superConstructor : superConstructors) { - if (superConstructor.getParameterList().getParametersCount() == 0) { - usages.add(new CopyDefaultConstructorUsageInfo(targetClass, superConstructor)); - break; - } + MultiMap conflictsMap = pushDownConflicts.getConflicts(); + for (PsiElement element : conflictsMap.keySet()) { + conflicts.put(element, conflictsMap.get(element)); } - } + if (myCurrentInheritor != null) { + ReferencesSearch.search(myCurrentInheritor).forEach(reference -> { + PsiElement element = reference.getElement(); + if (element != null && element.getParent() instanceof PsiNewExpression newExpr + && PsiUtil.resolveClassInType(getPlaceExpectedType(newExpr)) == mySuperClass) { + conflicts.putValue(newExpr, "Instance of target type is passed to a place where super class is expected."); + return false; + } + return true; + }); + } + checkConflicts(refUsages, conflicts); + return showConflicts(conflicts, refUsages.get()); } - } - @Override - protected boolean preprocessUsages(final Ref refUsages) { - final MultiMap conflicts = new MultiMap<>(); - final PushDownConflicts pushDownConflicts = new PushDownConflicts(mySuperClass, myMemberInfos); - for (PsiClass targetClass : myTargetClasses) { - for (MemberInfo info : myMemberInfos) { - final PsiMember member = info.getMember(); - pushDownConflicts.checkMemberPlacementInTargetClassConflict(targetClass, member); - } - //todo check accessibility conflicts - } - final MultiMap conflictsMap = pushDownConflicts.getConflicts(); - for (PsiElement element : conflictsMap.keySet()) { - conflicts.put(element, conflictsMap.get(element)); - } - if (myCurrentInheritor != null) { - ReferencesSearch.search(myCurrentInheritor).forEach(reference -> { - final PsiElement element = reference.getElement(); - if (element != null) { - final PsiElement parent = element.getParent(); - if (parent instanceof PsiNewExpression) { - final PsiClass aClass = PsiUtil.resolveClassInType(getPlaceExpectedType(parent)); - if (aClass == mySuperClass) { - conflicts.putValue(parent, "Instance of target type is passed to a place where super class is expected."); - return false; + @Nullable + private static PsiType getPlaceExpectedType(PsiElement parent) { + PsiType type = PsiTypesUtil.getExpectedTypeByParent(parent); + if (type == null) { + PsiElement arg = PsiUtil.skipParenthesizedExprUp(parent); + if (arg.getParent() instanceof PsiExpressionList exprList) { + int i = ArrayUtil.find(exprList.getExpressions(), arg); + if (exprList.getParent() instanceof PsiCallExpression callExpr) { + PsiMethod method = callExpr.resolveMethod(); + if (method != null) { + PsiParameter[] parameters = method.getParameterList().getParameters(); + if (i >= parameters.length) { + if (method.isVarArgs()) { + return ((PsiEllipsisType)parameters[parameters.length - 1].getType()).getComponentType(); + } + } + else { + return parameters[i].getType(); + } + } + } } - } } - return true; - }); + return type; } - checkConflicts(refUsages, conflicts); - return showConflicts(conflicts, refUsages.get()); - } - @Nullable - private static PsiType getPlaceExpectedType(PsiElement parent) { - PsiType type = PsiTypesUtil.getExpectedTypeByParent(parent); - if (type == null) { - final PsiElement arg = PsiUtil.skipParenthesizedExprUp(parent); - final PsiElement gParent = arg.getParent(); - if (gParent instanceof PsiExpressionList) { - int i = ArrayUtilRt.find(((PsiExpressionList) gParent).getExpressions(), arg); - final PsiElement pParent = gParent.getParent(); - if (pParent instanceof PsiCallExpression) { - final PsiMethod method = ((PsiCallExpression) pParent).resolveMethod(); - if (method != null) { - final PsiParameter[] parameters = method.getParameterList().getParameters(); - if (i >= parameters.length) { - if (method.isVarArgs()) { - return ((PsiEllipsisType) parameters[parameters.length - 1].getType()).getComponentType(); - } - } else { - return parameters[i].getType(); + @Override + @RequiredUIAccess + protected void performRefactoring(@Nonnull UsageInfo[] usages) { + new PushDownProcessor(mySuperClass.getProject(), myMemberInfos, mySuperClass, new DocCommentPolicy(myPolicy)) { + //push down conflicts are already collected + @Override + @RequiredUIAccess + protected boolean showConflicts(@Nonnull MultiMap conflicts, UsageInfo[] usages) { + return true; } - } - } - } - } - return type; - } - protected void performRefactoring(final UsageInfo[] usages) { - new PushDownProcessor(mySuperClass.getProject(), myMemberInfos, mySuperClass, new DocCommentPolicy(myPolicy)) { - //push down conflicts are already collected - @Override - protected boolean showConflicts(@Nonnull MultiMap conflicts, UsageInfo[] usages) { - return true; - } + @Override + @RequiredUIAccess + protected void performRefactoring(@Nonnull UsageInfo[] pushDownUsages) { + if (myCurrentInheritor != null) { + encodeRefs(); + pushDownToClass(myCurrentInheritor); + } + else { + super.performRefactoring(pushDownUsages); + } + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); + for (UsageInfo usageInfo : usages) { + if (!(usageInfo instanceof ReplaceExtendsListUsageInfo || usageInfo instanceof RemoveImportUsageInfo)) { + try { + ((FixableUsageInfo)usageInfo).fixUsage(); + } + catch (IncorrectOperationException e) { + LOG.info(e); + } + } + } + replaceInnerTypeUsages(); - @Override - @RequiredUIAccess - protected void performRefactoring(@Nonnull UsageInfo[] pushDownUsages) { - if (myCurrentInheritor != null) { - encodeRefs(); - pushDownToClass(myCurrentInheritor); - } else { - super.performRefactoring(pushDownUsages); - } - CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); - for (UsageInfo usageInfo : usages) { - if (!(usageInfo instanceof ReplaceExtendsListUsageInfo || usageInfo instanceof RemoveImportUsageInfo)) { - try { - ((FixableUsageInfo) usageInfo).fixUsage(); - } catch (IncorrectOperationException e) { - LOG.info(e); + //postpone broken hierarchy + for (UsageInfo usage : usages) { + if (usage instanceof ReplaceExtendsListUsageInfo || usage instanceof RemoveImportUsageInfo) { + ((FixableUsageInfo)usage).fixUsage(); + } + } + if (myCurrentInheritor == null) { + try { + mySuperClass.delete(); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } } - } - } - replaceInnerTypeUsages(); + }.run(); + } - //postpone broken hierarchy - for (UsageInfo usage : usages) { - if (usage instanceof ReplaceExtendsListUsageInfo || usage instanceof RemoveImportUsageInfo) { - ((FixableUsageInfo) usage).fixUsage(); - } - } - if (myCurrentInheritor == null) { - try { - mySuperClass.delete(); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - }.run(); - } + private void replaceInnerTypeUsages() { + JavaPsiFacade facade = JavaPsiFacade.getInstance(myProject); + PsiElementFactory elementFactory = facade.getElementFactory(); + PsiResolveHelper resolveHelper = facade.getResolveHelper(); + Map replacementMap = new HashMap<>(); + for (PsiClass targetClass : myTargetClasses) { + PsiSubstitutor superClassSubstitutor = + TypeConversionUtil.getSuperClassSubstitutor(mySuperClass, targetClass, PsiSubstitutor.EMPTY); + PsiClassType targetClassType = elementFactory.createType(targetClass, superClassSubstitutor); + targetClass.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + @RequiredReadAction + public void visitTypeElement(@Nonnull PsiTypeElement typeElement) { + super.visitTypeElement(typeElement); + PsiType superClassType = typeElement.getType(); + if (PsiUtil.resolveClassInType(superClassType) == mySuperClass) { + PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass); + replacementMap.put( + new UsageInfo(typeElement), + elementFactory.createTypeElement(elementFactory.createType(targetClass, subst)) + ); + } + } - private void replaceInnerTypeUsages() { - final JavaPsiFacade facade = JavaPsiFacade.getInstance(myProject); - final PsiElementFactory elementFactory = facade.getElementFactory(); - final PsiResolveHelper resolveHelper = facade.getResolveHelper(); - final Map replacementMap = new HashMap<>(); - for (final PsiClass targetClass : myTargetClasses) { - final PsiSubstitutor superClassSubstitutor = - TypeConversionUtil.getSuperClassSubstitutor(mySuperClass, targetClass, PsiSubstitutor.EMPTY); - final PsiClassType targetClassType = elementFactory.createType(targetClass, superClassSubstitutor); - targetClass.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitTypeElement(@Nonnull final PsiTypeElement typeElement) { - super.visitTypeElement(typeElement); - final PsiType superClassType = typeElement.getType(); - if (PsiUtil.resolveClassInType(superClassType) == mySuperClass) { - PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass); - replacementMap.put(new UsageInfo(typeElement), elementFactory.createTypeElement(elementFactory.createType(targetClass, subst))); - } + @Override + @RequiredReadAction + public void visitNewExpression(@Nonnull PsiNewExpression expression) { + super.visitNewExpression(expression); + PsiType superClassType = expression.getType(); + if (PsiUtil.resolveClassInType(superClassType) == mySuperClass) { + PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass); + try { + replacementMap.put( + new UsageInfo(expression), + elementFactory.createExpressionFromText( + "new " + elementFactory.createType(targetClass, subst).getCanonicalText() + + expression.getArgumentList().getText(), + expression + ) + ); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + }); } - - @Override - @RequiredReadAction - public void visitNewExpression(@Nonnull final PsiNewExpression expression) { - super.visitNewExpression(expression); - final PsiType superClassType = expression.getType(); - if (PsiUtil.resolveClassInType(superClassType) == mySuperClass) { - PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass); - try { - replacementMap.put(new UsageInfo(expression), elementFactory.createExpressionFromText("new " + elementFactory.createType( - targetClass, subst).getCanonicalText() + expression.getArgumentList().getText(), expression)); - } catch (IncorrectOperationException e) { - LOG.error(e); + try { + for (Map.Entry elementEntry : replacementMap.entrySet()) { + PsiElement element = elementEntry.getKey().getElement(); + if (element != null) { + element.replace(elementEntry.getValue()); + } } - } } - }); - } - try { - for (Map.Entry elementEntry : replacementMap.entrySet()) { - final PsiElement element = elementEntry.getKey().getElement(); - if (element != null) { - element.replace(elementEntry.getValue()); + catch (IncorrectOperationException e) { + LOG.error(e); } - } - } catch (IncorrectOperationException e) { - LOG.error(e); } - } - @RequiredReadAction - private static PsiSubstitutor getSuperClassSubstitutor( - final PsiType superClassType, - final PsiClassType targetClassType, - final PsiResolveHelper resolveHelper, - PsiClass targetClass - ) { - PsiSubstitutor subst = PsiSubstitutor.EMPTY; - for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(targetClass)) { - subst = subst.put( - typeParameter, - resolveHelper.getSubstitutionForTypeParameter( - typeParameter, - targetClassType, - superClassType, - false, - PsiUtil.getLanguageLevel(targetClass) - ) - ); + @RequiredReadAction + private static PsiSubstitutor getSuperClassSubstitutor( + PsiType superClassType, + PsiClassType targetClassType, + PsiResolveHelper resolveHelper, + PsiClass targetClass + ) { + PsiSubstitutor subst = PsiSubstitutor.EMPTY; + for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(targetClass)) { + subst = subst.put( + typeParameter, + resolveHelper.getSubstitutionForTypeParameter( + typeParameter, + targetClassType, + superClassType, + false, + PsiUtil.getLanguageLevel(targetClass) + ) + ); + } + return subst; } - return subst; - } - protected String getCommandName() { - return InlineSuperClassRefactoringHandler.REFACTORING_NAME; - } + @Nonnull + @Override + protected String getCommandName() { + return InlineSuperClassRefactoringHandler.REFACTORING_NAME; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java index e74ae1b15..441294e91 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java @@ -52,7 +52,7 @@ import consulo.util.collection.ArrayUtil; import consulo.util.collection.MultiMap; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -86,8 +86,10 @@ public IntroduceParameterObjectProcessor( String packageName, MoveDestination moveDestination, PsiMethod method, - VariableData[] parameters, boolean keepMethodAsDelegate, final boolean useExistingClass, - final boolean createInnerClass, + VariableData[] parameters, + boolean keepMethodAsDelegate, + boolean useExistingClass, + boolean createInnerClass, String newVisibility, boolean generateAccessors ) { @@ -105,26 +107,26 @@ public IntroduceParameterObjectProcessor( for (VariableData parameter : parameters) { this.parameters.add(new ParameterChunk(parameter)); } - final PsiParameterList parameterList = method.getParameterList(); - final PsiParameter[] methodParams = parameterList.getParameters(); + PsiParameterList parameterList = method.getParameterList(); + PsiParameter[] methodParams = parameterList.getParameters(); paramsToMerge = new int[parameters.length]; for (int p = 0; p < parameters.length; p++) { VariableData parameter = parameters[p]; for (int i = 0; i < methodParams.length; i++) { - final PsiParameter methodParam = methodParams[i]; + PsiParameter methodParam = methodParams[i]; if (parameter.variable.equals(methodParam)) { paramsToMerge[p] = i; break; } } } - final Set typeParamSet = new HashSet<>(); - final PsiTypeVisitor typeParametersVisitor = new PsiTypeVisitor<>() { + Set typeParamSet = new HashSet<>(); + PsiTypeVisitor typeParametersVisitor = new PsiTypeVisitor<>() { @Override public Object visitClassType(PsiClassType classType) { - final PsiClass referent = classType.resolve(); - if (referent instanceof PsiTypeParameter) { - typeParamSet.add((PsiTypeParameter)referent); + PsiClass referent = classType.resolve(); + if (referent instanceof PsiTypeParameter typeParameter) { + typeParamSet.add(typeParameter); } return super.visitClassType(classType); } @@ -134,8 +136,8 @@ public Object visitClassType(PsiClassType classType) { } typeParams = new ArrayList<>(typeParamSet); - final String qualifiedName = StringUtil.getQualifiedName(packageName, className); - final GlobalSearchScope scope = GlobalSearchScope.allScope(myProject); + String qualifiedName = StringUtil.getQualifiedName(packageName, className); + GlobalSearchScope scope = GlobalSearchScope.allScope(myProject); existingClass = JavaPsiFacade.getInstance(myProject).findClass(qualifiedName, scope); } @@ -147,7 +149,7 @@ protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usa @Override @RequiredUIAccess - protected boolean preprocessUsages(@Nonnull final Ref refUsages) { + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { MultiMap conflicts = new MultiMap<>(); if (myUseExistingClass) { if (existingClass == null) { @@ -183,8 +185,8 @@ protected boolean preprocessUsages(@Nonnull final Ref refUsages) { } } for (UsageInfo usageInfo : refUsages.get()) { - if (usageInfo instanceof FixableUsageInfo) { - final String conflictMessage = ((FixableUsageInfo)usageInfo).getConflictMessage(); + if (usageInfo instanceof FixableUsageInfo fixableUsageInfo) { + String conflictMessage = fixableUsageInfo.getConflictMessage(); if (conflictMessage != null) { conflicts.putValue(usageInfo.getElement(), conflictMessage); } @@ -211,7 +213,7 @@ public void findUsages(@Nonnull List usages) { )); } - final PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY); + PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY); for (PsiMethod siblingMethod : overridingMethods) { findUsagesForMethod(siblingMethod, usages, false); } @@ -228,9 +230,9 @@ public void findUsages(@Nonnull List usages) { @RequiredReadAction private void findUsagesForMethod(PsiMethod overridingMethod, List usages, boolean changeSignature) { - final PsiCodeBlock body = overridingMethod.getBody(); - final String baseParameterName = StringUtil.decapitalize(className); - final String fixedParamName = body != null + PsiCodeBlock body = overridingMethod.getBody(); + String baseParameterName = StringUtil.decapitalize(className); + String fixedParamName = body != null ? JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(baseParameterName, body.getLBrace(), true) : JavaCodeStyleManager.getInstance(myProject).propertyNameToVariableName(baseParameterName, VariableKind.PARAMETER); @@ -246,16 +248,16 @@ private void findUsagesForMethod(PsiMethod overridingMethod, List values = visitor.getParameterUsages(); + Set values = visitor.getParameterUsages(); for (PsiReferenceExpression paramUsage : values) { - final PsiParameter parameter = (PsiParameter)paramUsage.resolve(); + PsiParameter parameter = (PsiParameter)paramUsage.resolve(); assert parameter != null; - final PsiMethod containingMethod = (PsiMethod)parameter.getDeclarationScope(); - final int index = containingMethod.getParameterList().getParameterIndex(parameter); - final PsiParameter replacedParameter = method.getParameterList().getParameters()[index]; - final ParameterChunk parameterChunk = ParameterChunk.getChunkByParameter(parameter, parameters); + PsiMethod containingMethod = (PsiMethod)parameter.getDeclarationScope(); + int index = containingMethod.getParameterList().getParameterIndex(parameter); + PsiParameter replacedParameter = method.getParameterList().getParameters()[index]; + ParameterChunk parameterChunk = ParameterChunk.getChunkByParameter(parameter, parameters); String getter = parameterChunk != null ? parameterChunk.getter : null; if (getter == null) { @@ -286,14 +288,14 @@ else if (RefactoringUtil.isAssignmentLHS(paramUsage)) { @Override @RequiredReadAction - protected void performRefactoring(UsageInfo[] usageInfos) { - final PsiClass psiClass = buildClass(); + protected void performRefactoring(@Nonnull UsageInfo[] usageInfos) { + PsiClass psiClass = buildClass(); if (psiClass != null) { fixJavadocForConstructor(psiClass); super.performRefactoring(usageInfos); if (!myUseExistingClass) { for (PsiReference reference : ReferencesSearch.search(method)) { - final PsiElement place = reference.getElement(); + PsiElement place = reference.getElement(); VisibilityUtil.escalateVisibility(psiClass, place); for (PsiMethod constructor : psiClass.getConstructors()) { VisibilityUtil.escalateVisibility(constructor, place); @@ -308,46 +310,46 @@ private PsiClass buildClass() { if (existingClass != null) { return existingClass; } - final ParameterObjectBuilder beanClassBuilder = new ParameterObjectBuilder(); + ParameterObjectBuilder beanClassBuilder = new ParameterObjectBuilder(); beanClassBuilder.setVisibility(myCreateInnerClass ? PsiModifier.PRIVATE : PsiModifier.PUBLIC); beanClassBuilder.setProject(myProject); beanClassBuilder.setTypeArguments(typeParams); beanClassBuilder.setClassName(className); beanClassBuilder.setPackageName(packageName); for (ParameterChunk parameterChunk : parameters) { - final VariableData parameter = parameterChunk.parameter; - final boolean setterRequired = paramsNeedingSetters.contains(parameter.variable); + VariableData parameter = parameterChunk.parameter; + boolean setterRequired = paramsNeedingSetters.contains(parameter.variable); beanClassBuilder.addField((PsiParameter)parameter.variable, parameter.name, parameter.type, setterRequired); } - final String classString = beanClassBuilder.buildBeanClass(); + String classString = beanClassBuilder.buildBeanClass(); try { - final PsiFileFactory factory = PsiFileFactory.getInstance(method.getProject()); - final PsiJavaFile newFile = (PsiJavaFile)factory.createFileFromText(className + ".java", JavaFileType.INSTANCE, classString); + PsiFileFactory factory = PsiFileFactory.getInstance(method.getProject()); + PsiJavaFile newFile = (PsiJavaFile)factory.createFileFromText(className + ".java", JavaFileType.INSTANCE, classString); if (myCreateInnerClass) { - final PsiClass containingClass = method.getContainingClass(); - final PsiClass[] classes = newFile.getClasses(); + PsiClass containingClass = method.getContainingClass(); + PsiClass[] classes = newFile.getClasses(); assert classes.length > 0 : classString; - final PsiClass innerClass = (PsiClass)containingClass.add(classes[0]); + PsiClass innerClass = (PsiClass)containingClass.add(classes[0]); PsiUtil.setModifierProperty(innerClass, PsiModifier.STATIC, true); return (PsiClass)JavaCodeStyleManager.getInstance(newFile.getProject()).shortenClassReferences(innerClass); } else { - final PsiFile containingFile = method.getContainingFile(); - final PsiDirectory containingDirectory = containingFile.getContainingDirectory(); - final PsiDirectory directory; + PsiFile containingFile = method.getContainingFile(); + PsiDirectory containingDirectory = containingFile.getContainingDirectory(); + PsiDirectory directory; if (myMoveDestination != null) { directory = myMoveDestination.getTargetDirectory(containingDirectory); } else { - final Module module = ModuleUtil.findModuleForPsiElement(containingFile); + Module module = ModuleUtil.findModuleForPsiElement(containingFile); directory = PackageUtil.findOrCreateDirectoryForPackage(module, packageName, containingDirectory, true, true); } if (directory != null) { - final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(method.getManager().getProject()); - final PsiElement shortenedFile = JavaCodeStyleManager.getInstance(newFile.getProject()).shortenClassReferences(newFile); - final PsiElement reformattedFile = codeStyleManager.reformat(shortenedFile); + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(method.getManager().getProject()); + PsiElement shortenedFile = JavaCodeStyleManager.getInstance(newFile.getProject()).shortenClassReferences(newFile); + PsiElement reformattedFile = codeStyleManager.reformat(shortenedFile); return ((PsiJavaFile)directory.add(reformattedFile)).getClasses()[0]; } } @@ -360,17 +362,17 @@ private PsiClass buildClass() { @RequiredReadAction private void fixJavadocForConstructor(PsiClass psiClass) { - final PsiDocComment docComment = method.getDocComment(); + PsiDocComment docComment = method.getDocComment(); if (docComment != null) { - final List mergedTags = new ArrayList<>(); - final PsiDocTag[] paramTags = docComment.findTagsByName("param"); + List mergedTags = new ArrayList<>(); + PsiDocTag[] paramTags = docComment.findTagsByName("param"); for (PsiDocTag paramTag : paramTags) { - final PsiElement[] dataElements = paramTag.getDataElements(); + PsiElement[] dataElements = paramTag.getDataElements(); if (dataElements.length > 0) { if (dataElements[0] instanceof PsiDocParamRef docParamRef) { - final PsiReference reference = docParamRef.getReference(); + PsiReference reference = docParamRef.getReference(); if (reference != null && reference.resolve() instanceof PsiParameter parameter) { - final int parameterIndex = method.getParameterList().getParameterIndex(parameter); + int parameterIndex = method.getParameterList().getParameterIndex(parameter); if (ArrayUtil.find(paramsToMerge, parameterIndex) < 0) { continue; } @@ -406,7 +408,7 @@ else if (!myUseExistingClass) { @Override @RequiredReadAction protected String getCommandName() { - final PsiClass containingClass = method.getContainingClass(); + PsiClass containingClass = method.getContainingClass(); return JavaRefactoringLocalize.introducedParameterClassCommandName(className, containingClass.getName(), method.getName()).get(); } @@ -416,8 +418,8 @@ private static class ParamUsageVisitor extends JavaRecursiveElementVisitor { ParamUsageVisitor(PsiMethod method, int[] paramIndicesToMerge) { super(); - final PsiParameterList paramList = method.getParameterList(); - final PsiParameter[] parameters = paramList.getParameters(); + PsiParameterList paramList = method.getParameterList(); + PsiParameter[] parameters = paramList.getParameters(); for (int i : paramIndicesToMerge) { paramsToMerge.add(parameters[i]); } @@ -427,7 +429,7 @@ private static class ParamUsageVisitor extends JavaRecursiveElementVisitor { @RequiredReadAction public void visitReferenceExpression(PsiReferenceExpression expression) { super.visitReferenceExpression(expression); - final PsiElement referent = expression.resolve(); + PsiElement referent = expression.resolve(); if (referent instanceof PsiParameter parameter && paramsToMerge.contains(parameter)) { parameterUsages.add(expression); } @@ -441,8 +443,8 @@ public Set getParameterUsages() { @Nullable private static PsiMethod existingClassIsCompatible(PsiClass aClass, List params) { if (params.size() == 1) { - final ParameterChunk parameterChunk = params.get(0); - final PsiType paramType = parameterChunk.parameter.type; + ParameterChunk parameterChunk = params.get(0); + PsiType paramType = parameterChunk.parameter.type; if (TypeConversionUtil.isPrimitiveWrapper(aClass.getQualifiedName())) { parameterChunk.setField(aClass.findFieldByName("value", false)); parameterChunk.setGetter(paramType.getCanonicalText() + "Value"); @@ -453,7 +455,7 @@ private static PsiMethod existingClassIsCompatible(PsiClass aClass, List params) { - final PsiParameterList parameterList = constructor.getParameterList(); - final PsiParameter[] constructorParams = parameterList.getParameters(); + PsiParameterList parameterList = constructor.getParameterList(); + PsiParameter[] constructorParams = parameterList.getParameters(); if (constructorParams.length != params.size()) { return false; } @@ -543,7 +545,7 @@ public static ParameterChunk getChunkByParameter(PsiParameter param, List myToInvert = new HashMap(); - private final SmartPointerManager mySmartPointerManager; + private PsiNamedElement myElement; + private final String myNewName; + private final RenameProcessor myRenameProcessor; + private final Map myToInvert = new HashMap<>(); + private final SmartPointerManager mySmartPointerManager; - public InvertBooleanProcessor(final PsiNamedElement namedElement, final String newName) { - super(namedElement.getProject()); - myElement = namedElement; - myNewName = newName; - final Project project = namedElement.getProject(); - myRenameProcessor = new RenameProcessor(project, namedElement, newName, false, false); - mySmartPointerManager = SmartPointerManager.getInstance(project); - } + public InvertBooleanProcessor(PsiNamedElement namedElement, String newName) { + super(namedElement.getProject()); + myElement = namedElement; + myNewName = newName; + Project project = namedElement.getProject(); + myRenameProcessor = new RenameProcessor(project, namedElement, newName, false, false); + mySmartPointerManager = SmartPointerManager.getInstance(project); + } - @Override - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new InvertBooleanUsageViewDescriptor(myElement); - } + @Override + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new InvertBooleanUsageViewDescriptor(myElement); + } - @Override - protected boolean preprocessUsages(Ref refUsages) { - if (myRenameProcessor.preprocessUsages(refUsages)) { - prepareSuccessful(); - return true; + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + if (myRenameProcessor.preprocessUsages(refUsages)) { + prepareSuccessful(); + return true; + } + return false; } - return false; - } - @Override - @Nonnull - protected UsageInfo[] findUsages() { - final List toInvert = new ArrayList(); + @Nonnull + @Override + @RequiredReadAction + protected UsageInfo[] findUsages() { + List toInvert = new ArrayList<>(); - addRefsToInvert(toInvert, myElement); + addRefsToInvert(toInvert, myElement); - if (myElement instanceof PsiMethod) { - final Collection overriders = OverridingMethodsSearch.search((PsiMethod)myElement).findAll(); - for (PsiMethod overrider : overriders) { - myRenameProcessor.addElement(overrider, myNewName); - } + if (myElement instanceof PsiMethod) { + Collection overriders = OverridingMethodsSearch.search((PsiMethod)myElement).findAll(); + for (PsiMethod overrider : overriders) { + myRenameProcessor.addElement(overrider, myNewName); + } - Collection allMethods = new HashSet(overriders); - allMethods.add((PsiMethod)myElement); + Collection allMethods = new HashSet<>(overriders); + allMethods.add((PsiMethod)myElement); - for (PsiMethod method : allMethods) { - method.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReturnStatement(PsiReturnStatement statement) { - final PsiExpression returnValue = statement.getReturnValue(); - if (returnValue != null && PsiType.BOOLEAN.equals(returnValue.getType())) { - toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(returnValue)); - } - } + for (PsiMethod method : allMethods) { + method.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReturnStatement(@Nonnull PsiReturnStatement statement) { + PsiExpression returnValue = statement.getReturnValue(); + if (returnValue != null && PsiType.BOOLEAN.equals(returnValue.getType())) { + toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(returnValue)); + } + } - @Override - public void visitClass(PsiClass aClass) { - } - }); - } - } else if (myElement instanceof PsiParameter && ((PsiParameter)myElement).getDeclarationScope() instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)((PsiParameter)myElement).getDeclarationScope(); - int index = method.getParameterList().getParameterIndex((PsiParameter)myElement); - LOG.assertTrue(index >= 0); - final Query methodQuery = MethodReferencesSearch.search(method); - final Collection methodRefs = methodQuery.findAll(); - for (PsiReference ref : methodRefs) { - PsiElement parent = ref.getElement().getParent(); - if (parent instanceof PsiAnonymousClass) { - parent = parent.getParent(); + @Override + public void visitClass(@Nonnull PsiClass aClass) { + } + }); + } } - if (parent instanceof PsiCall) { - final PsiCall call = (PsiCall)parent; - final PsiReferenceExpression methodExpression = call instanceof PsiMethodCallExpression ? - ((PsiMethodCallExpression)call).getMethodExpression() : - null; - final PsiExpressionList argumentList = call.getArgumentList(); - if (argumentList != null) { - final PsiExpression[] args = argumentList.getExpressions(); - if (index < args.length) { - if (methodExpression == null || methodExpression.getQualifier() == null || !"super".equals(methodExpression.getQualifierExpression().getText())) { - toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(args[index])); - } + else if (myElement instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiMethod) { + PsiMethod method = (PsiMethod)parameter.getDeclarationScope(); + int index = method.getParameterList().getParameterIndex(parameter); + LOG.assertTrue(index >= 0); + Query methodQuery = MethodReferencesSearch.search(method); + Collection methodRefs = methodQuery.findAll(); + for (PsiReference ref : methodRefs) { + PsiElement parent = ref.getElement().getParent(); + if (parent instanceof PsiAnonymousClass) { + parent = parent.getParent(); + } + if (parent instanceof PsiCall call) { + PsiReferenceExpression methodExpression = call instanceof PsiMethodCallExpression methodCall + ? methodCall.getMethodExpression() + : null; + PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList != null) { + PsiExpression[] args = argumentList.getExpressions(); + if (index < args.length + && (methodExpression == null || methodExpression.getQualifier() == null + || !"super".equals(methodExpression.getQualifierExpression().getText()))) { + toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(args[index])); + } + } + } + } + Collection overriders = OverridingMethodsSearch.search(method).findAll(); + for (PsiMethod overrider : overriders) { + PsiParameter overriderParameter = overrider.getParameterList().getParameters()[index]; + myRenameProcessor.addElement(overriderParameter, myNewName); + addRefsToInvert(toInvert, overriderParameter); } - } } - } - final Collection overriders = OverridingMethodsSearch.search(method).findAll(); - for (PsiMethod overrider : overriders) { - final PsiParameter overriderParameter = overrider.getParameterList().getParameters()[index]; - myRenameProcessor.addElement(overriderParameter, myNewName); - addRefsToInvert(toInvert, overriderParameter); - } - } - final UsageInfo[] renameUsages = myRenameProcessor.findUsages(); + UsageInfo[] renameUsages = myRenameProcessor.findUsages(); - final SmartPsiElementPointer[] usagesToInvert = toInvert.toArray(new SmartPsiElementPointer[toInvert.size()]); + SmartPsiElementPointer[] usagesToInvert = toInvert.toArray(new SmartPsiElementPointer[toInvert.size()]); - //merge rename and invert usages - Map expressionsToUsages = new HashMap(); - List result = new ArrayList(); - for (UsageInfo renameUsage : renameUsages) { - expressionsToUsages.put(renameUsage.getElement(), renameUsage); - result.add(renameUsage); - } + //merge rename and invert usages + Map expressionsToUsages = new HashMap<>(); + List result = new ArrayList<>(); + for (UsageInfo renameUsage : renameUsages) { + expressionsToUsages.put(renameUsage.getElement(), renameUsage); + result.add(renameUsage); + } - for (SmartPsiElementPointer pointer : usagesToInvert) { - final PsiExpression expression = (PsiExpression)pointer.getElement(); - if (!expressionsToUsages.containsKey(expression)) { - final UsageInfo usageInfo = new UsageInfo(expression); - expressionsToUsages.put(expression, usageInfo); - result.add(usageInfo); //fake UsageInfo - myToInvert.put(usageInfo, pointer); - } else { - myToInvert.put(expressionsToUsages.get(expression), pointer); - } + for (SmartPsiElementPointer pointer : usagesToInvert) { + PsiExpression expression = (PsiExpression)pointer.getElement(); + if (!expressionsToUsages.containsKey(expression)) { + UsageInfo usageInfo = new UsageInfo(expression); + expressionsToUsages.put(expression, usageInfo); + result.add(usageInfo); //fake UsageInfo + myToInvert.put(usageInfo, pointer); + } + else { + myToInvert.put(expressionsToUsages.get(expression), pointer); + } + } + + return result.toArray(new UsageInfo[result.size()]); } - return result.toArray(new UsageInfo[result.size()]); - } + @RequiredReadAction + private void addRefsToInvert(List toInvert, PsiNamedElement namedElement) { + Query query = namedElement instanceof PsiMethod method + ? MethodReferencesSearch.search(method) + : ReferencesSearch.search(namedElement); + Collection refs = query.findAll(); - private void addRefsToInvert(final List toInvert, final PsiNamedElement namedElement) { - final Query query = namedElement instanceof PsiMethod ? - MethodReferencesSearch.search((PsiMethod)namedElement) : - ReferencesSearch.search(namedElement); - final Collection refs = query.findAll(); + for (PsiReference ref : refs) { + PsiElement element = ref.getElement(); + if (element instanceof PsiReferenceExpression refExpr) { + if (refExpr.getParent() instanceof PsiAssignmentExpression assignment && refExpr.equals(assignment.getLExpression())) { + toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(assignment.getRExpression())); + } + else { + if (namedElement instanceof PsiParameter + && refExpr.getParent().getParent() instanceof PsiMethodCallExpression methodCall) { + PsiReferenceExpression methodExpr = methodCall.getMethodExpression(); + if (methodExpr.getQualifier() != null && "super".equals(methodExpr.getQualifierExpression().getText())) { + continue; + } + } - for (PsiReference ref : refs) { - final PsiElement element = ref.getElement(); - if (element instanceof PsiReferenceExpression) { - final PsiReferenceExpression refExpr = (PsiReferenceExpression)element; - PsiElement parent = refExpr.getParent(); - if (parent instanceof PsiAssignmentExpression && refExpr.equals(((PsiAssignmentExpression)parent).getLExpression())) { - toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(((PsiAssignmentExpression)parent).getRExpression())); - } - else { - if (namedElement instanceof PsiParameter) { //filter usages in super method calls - if (refExpr.getParent().getParent() instanceof PsiMethodCallExpression) { - final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)refExpr.getParent().getParent()).getMethodExpression(); - if (methodExpression.getQualifier() != null && "super".equals(methodExpression.getQualifierExpression().getText())) { - continue; - } + toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(refExpr)); + } } - } + } - toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(refExpr)); + if (namedElement instanceof PsiVariable variable) { + PsiExpression initializer = variable.getInitializer(); + if (initializer != null) { + toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(initializer)); + } } - } } - if (namedElement instanceof PsiVariable) { - final PsiExpression initializer = ((PsiVariable)namedElement).getInitializer(); - if (initializer != null) { - toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(initializer)); - } + @Override + protected void refreshElements(PsiElement[] elements) { + LOG.assertTrue(elements.length == 1 && elements[0] instanceof PsiMethod); + myElement = (PsiMethod)elements[0]; } - } - @Override - protected void refreshElements(PsiElement[] elements) { - LOG.assertTrue(elements.length == 1 && elements[0] instanceof PsiMethod); - myElement = (PsiMethod)elements[0]; - } - - private static UsageInfo[] extractUsagesForElement(PsiElement element, UsageInfo[] usages) { - final ArrayList extractedUsages = new ArrayList(usages.length); - for (UsageInfo usage : usages) { - if (usage instanceof MoveRenameUsageInfo) { - MoveRenameUsageInfo usageInfo = (MoveRenameUsageInfo)usage; - if (element.equals(usageInfo.getReferencedElement())) { - extractedUsages.add(usageInfo); + private static UsageInfo[] extractUsagesForElement(PsiElement element, UsageInfo[] usages) { + ArrayList extractedUsages = new ArrayList<>(usages.length); + for (UsageInfo usage : usages) { + if (usage instanceof MoveRenameUsageInfo) { + MoveRenameUsageInfo usageInfo = (MoveRenameUsageInfo)usage; + if (element.equals(usageInfo.getReferencedElement())) { + extractedUsages.add(usageInfo); + } + } } - } + return extractedUsages.toArray(new UsageInfo[extractedUsages.size()]); } - return extractedUsages.toArray(new UsageInfo[extractedUsages.size()]); - } - - @Override - protected void performRefactoring(UsageInfo[] usages) { - for (final PsiElement element : myRenameProcessor.getElements()) { - try { - RenameUtil.doRename(element, myRenameProcessor.getNewName(element), extractUsagesForElement(element, usages), myProject, null); - } - catch (final IncorrectOperationException e) { - RenameUtil.showErrorMessage(e, element, myProject); - return; - } - } + @Override + @RequiredReadAction + protected void performRefactoring(@Nonnull UsageInfo[] usages) { + for (PsiElement element : myRenameProcessor.getElements()) { + try { + RenameUtil.doRename( + element, + myRenameProcessor.getNewName(element), + extractUsagesForElement(element, usages), + myProject, + null + ); + } + catch (IncorrectOperationException e) { + RenameUtil.showErrorMessage(e, element, myProject); + return; + } + } + for (UsageInfo usage : usages) { + SmartPsiElementPointer pointerToInvert = myToInvert.get(usage); + if (pointerToInvert != null) { + PsiExpression expression = (PsiExpression)pointerToInvert.getElement(); + LOG.assertTrue(expression != null); + if (expression.getParent() instanceof PsiMethodCallExpression methodCall) { + expression = methodCall; + } + try { + while (expression.getParent() instanceof PsiPrefixExpression prefixExpr + && prefixExpr.getOperationTokenType() == JavaTokenType.EXCL) { + expression = prefixExpr; + } - for (UsageInfo usage : usages) { - final SmartPsiElementPointer pointerToInvert = myToInvert.get(usage); - if (pointerToInvert != null) { - PsiExpression expression = (PsiExpression)pointerToInvert.getElement(); - LOG.assertTrue(expression != null); - if (expression.getParent() instanceof PsiMethodCallExpression) expression = (PsiExpression)expression.getParent(); - try { - while (expression.getParent() instanceof PsiPrefixExpression && - ((PsiPrefixExpression)expression.getParent()).getOperationTokenType() == JavaTokenType.EXCL) { - expression = (PsiExpression)expression.getParent(); - } - if (!(expression.getParent() instanceof PsiExpressionStatement)) { - expression.replace(CodeInsightServicesUtil.invertCondition(expression)); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); + if (!(expression.getParent() instanceof PsiExpressionStatement)) { + expression.replace(CodeInsightServicesUtil.invertCondition(expression)); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } } - } } - } - @Override - protected String getCommandName() { - return InvertBooleanHandler.REFACTORING_NAME; - } + @Nonnull + @Override + protected String getCommandName() { + return InvertBooleanHandler.REFACTORING_NAME; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationProcessor.java index 3a637fef9..4d5f8891e 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationProcessor.java @@ -18,11 +18,11 @@ import com.intellij.java.impl.psi.impl.migration.PsiMigrationManager; import com.intellij.java.language.psi.PsiMigration; import com.intellij.java.language.psi.codeStyle.JavaCodeStyleManager; -import consulo.application.ApplicationManager; +import consulo.annotation.access.RequiredReadAction; +import consulo.application.Application; import consulo.application.WriteAction; import consulo.content.scope.SearchScope; import consulo.language.editor.refactoring.BaseRefactoringProcessor; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.psi.PsiElement; import consulo.language.psi.SmartPsiElementPointer; @@ -36,197 +36,175 @@ import consulo.usage.UsageViewDescriptor; import consulo.util.lang.Comparing; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; - +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; + import java.util.ArrayList; /** * @author ven */ -public class MigrationProcessor extends BaseRefactoringProcessor -{ - private final MigrationMap myMigrationMap; - private static final String REFACTORING_NAME = RefactoringBundle.message("migration.title"); - private PsiMigration myPsiMigration; - private final SearchScope mySearchScope; - private ArrayList> myRefsToShorten; - - public MigrationProcessor(Project project, MigrationMap migrationMap) - { - this(project, migrationMap, GlobalSearchScope.projectScope(project)); - } - - public MigrationProcessor(Project project, MigrationMap migrationMap, SearchScope scope) - { - super(project); - myMigrationMap = migrationMap; - mySearchScope = scope; - myPsiMigration = startMigration(project); - } - - @Override - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) - { - return new MigrationUsagesViewDescriptor(myMigrationMap, false); - } - - private PsiMigration startMigration(Project project) - { - final PsiMigration migration = PsiMigrationManager.getInstance(project).startMigration(); - findOrCreateEntries(project, migration); - return migration; - } - - private void findOrCreateEntries(Project project, final PsiMigration migration) - { - for (int i = 0; i < myMigrationMap.getEntryCount(); i++) - { - MigrationMapEntry entry = myMigrationMap.getEntryAt(i); - if (entry.getType() == MigrationMapEntry.PACKAGE) - { - MigrationUtil.findOrCreatePackage(project, migration, entry.getOldName()); - } - else - { - MigrationUtil.findOrCreateClass(project, migration, entry.getOldName()); - } - } - } - - @Override - protected void refreshElements(@Nonnull PsiElement[] elements) - { - myPsiMigration = startMigration(myProject); - } - - @Override - @Nonnull - protected UsageInfo[] findUsages() - { - ArrayList usagesVector = new ArrayList<>(); - try - { - if (myMigrationMap == null) - { - return UsageInfo.EMPTY_ARRAY; - } - for (int i = 0; i < myMigrationMap.getEntryCount(); i++) - { - MigrationMapEntry entry = myMigrationMap.getEntryAt(i); - UsageInfo[] usages; - if (entry.getType() == MigrationMapEntry.PACKAGE) - { - usages = MigrationUtil.findPackageUsages(myProject, myPsiMigration, entry.getOldName(), mySearchScope); - } - else - { - usages = MigrationUtil.findClassUsages(myProject, myPsiMigration, entry.getOldName(), mySearchScope); - } - - for (UsageInfo usage : usages) - { - usagesVector.add(new MigrationUsageInfo(usage, entry)); - } - } - } - finally - { - //invalidating resolve caches without write action could lead to situations when somebody with read action resolves reference and gets ResolveResult - //then here, in another read actions, all caches are invalidated but those resolve result is used without additional checks inside that read action - but it's already invalid - ApplicationManager.getApplication().invokeLater(() -> WriteAction.run(this::finishFindMigration), myProject.getDisposed()); - } - return usagesVector.toArray(UsageInfo.EMPTY_ARRAY); - } - - private void finishFindMigration() - { - if (myPsiMigration != null) - { - myPsiMigration.finish(); - myPsiMigration = null; - } - } - - @Override - @RequiredUIAccess - protected boolean preprocessUsages(@Nonnull Ref refUsages) - { - if (refUsages.get().length == 0) - { - Messages.showInfoMessage(myProject, RefactoringLocalize.migrationNoUsagesFoundInTheProject().get(), REFACTORING_NAME); - return false; - } - setPreviewUsages(true); - return true; - } - - @Override - protected void performRefactoring(@Nonnull UsageInfo[] usages) - { - finishFindMigration(); - final PsiMigration psiMigration = PsiMigrationManager.getInstance(myProject).startMigration(); - LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName()); - - myRefsToShorten = new ArrayList<>(); - try - { - boolean sameShortNames = false; - for (int i = 0; i < myMigrationMap.getEntryCount(); i++) - { - MigrationMapEntry entry = myMigrationMap.getEntryAt(i); - String newName = entry.getNewName(); - PsiElement element = entry.getType() == MigrationMapEntry.PACKAGE ? MigrationUtil.findOrCreatePackage(myProject, psiMigration, newName) : MigrationUtil.findOrCreateClass(myProject, - psiMigration, newName); - MigrationUtil.doMigration(element, newName, usages, myRefsToShorten); - if (!sameShortNames && Comparing.strEqual(StringUtil.getShortName(entry.getOldName()), StringUtil.getShortName(entry.getNewName()))) - { - sameShortNames = true; - } - } - - if (!sameShortNames) - { - myRefsToShorten.clear(); - } - } - finally - { - a.finish(); - psiMigration.finish(); - } - } - - @Override - protected void performPsiSpoilingRefactoring() - { - JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); - for (SmartPsiElementPointer pointer : myRefsToShorten) - { - PsiElement element = pointer.getElement(); - if (element != null) - { - styleManager.shortenClassReferences(element); - } - } - } - - @Override - @Nonnull - protected String getCommandName() - { - return REFACTORING_NAME; - } - - static class MigrationUsageInfo extends UsageInfo - { - MigrationMapEntry mapEntry; - - MigrationUsageInfo(UsageInfo info, MigrationMapEntry mapEntry) - { - super(info.getElement(), info.getRangeInElement().getStartOffset(), info.getRangeInElement().getEndOffset()); - this.mapEntry = mapEntry; - } - } +public class MigrationProcessor extends BaseRefactoringProcessor { + private final MigrationMap myMigrationMap; + private PsiMigration myPsiMigration; + private final SearchScope mySearchScope; + private ArrayList> myRefsToShorten; + + public MigrationProcessor(Project project, MigrationMap migrationMap) { + this(project, migrationMap, GlobalSearchScope.projectScope(project)); + } + + public MigrationProcessor(Project project, MigrationMap migrationMap, SearchScope scope) { + super(project); + myMigrationMap = migrationMap; + mySearchScope = scope; + myPsiMigration = startMigration(project); + } + + @Override + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new MigrationUsagesViewDescriptor(myMigrationMap, false); + } + + private PsiMigration startMigration(Project project) { + PsiMigration migration = PsiMigrationManager.getInstance(project).startMigration(); + findOrCreateEntries(project, migration); + return migration; + } + + private void findOrCreateEntries(Project project, PsiMigration migration) { + for (int i = 0; i < myMigrationMap.getEntryCount(); i++) { + MigrationMapEntry entry = myMigrationMap.getEntryAt(i); + if (entry.getType() == MigrationMapEntry.PACKAGE) { + MigrationUtil.findOrCreatePackage(project, migration, entry.getOldName()); + } + else { + MigrationUtil.findOrCreateClass(project, migration, entry.getOldName()); + } + } + } + + @Override + protected void refreshElements(@Nonnull PsiElement[] elements) { + myPsiMigration = startMigration(myProject); + } + + @Nonnull + @Override + @RequiredReadAction + protected UsageInfo[] findUsages() { + ArrayList usagesVector = new ArrayList<>(); + try { + if (myMigrationMap == null) { + return UsageInfo.EMPTY_ARRAY; + } + for (int i = 0; i < myMigrationMap.getEntryCount(); i++) { + MigrationMapEntry entry = myMigrationMap.getEntryAt(i); + UsageInfo[] usages; + if (entry.getType() == MigrationMapEntry.PACKAGE) { + usages = MigrationUtil.findPackageUsages(myProject, myPsiMigration, entry.getOldName(), mySearchScope); + } + else { + usages = MigrationUtil.findClassUsages(myProject, myPsiMigration, entry.getOldName(), mySearchScope); + } + + for (UsageInfo usage : usages) { + usagesVector.add(new MigrationUsageInfo(usage, entry)); + } + } + } + finally { + // Invalidating resolve caches without write action could lead to situations + // when somebody with read action resolves reference and gets ResolveResult. + // Then here, in another read actions, all caches are invalidated but those resolve result + // is used without additional checks inside that read action - but it's already invalid + Application.get().invokeLater(() -> WriteAction.run(this::finishFindMigration), myProject.getDisposed()); + } + return usagesVector.toArray(UsageInfo.EMPTY_ARRAY); + } + + private void finishFindMigration() { + if (myPsiMigration != null) { + myPsiMigration.finish(); + myPsiMigration = null; + } + } + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + if (refUsages.get().length == 0) { + Messages.showInfoMessage( + myProject, + RefactoringLocalize.migrationNoUsagesFoundInTheProject().get(), + RefactoringLocalize.migrationTitle().get() + ); + return false; + } + setPreviewUsages(true); + return true; + } + + @Override + protected void performRefactoring(@Nonnull UsageInfo[] usages) { + finishFindMigration(); + PsiMigration psiMigration = PsiMigrationManager.getInstance(myProject).startMigration(); + LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName()); + + myRefsToShorten = new ArrayList<>(); + try { + boolean sameShortNames = false; + for (int i = 0; i < myMigrationMap.getEntryCount(); i++) { + MigrationMapEntry entry = myMigrationMap.getEntryAt(i); + String newName = entry.getNewName(); + PsiElement element = entry.getType() == MigrationMapEntry.PACKAGE + ? MigrationUtil.findOrCreatePackage(myProject, psiMigration, newName) + : MigrationUtil.findOrCreateClass(myProject, psiMigration, newName); + MigrationUtil.doMigration(element, newName, usages, myRefsToShorten); + if (!sameShortNames && Comparing.strEqual( + StringUtil.getShortName(entry.getOldName()), + StringUtil.getShortName(entry.getNewName()) + )) { + sameShortNames = true; + } + } + + if (!sameShortNames) { + myRefsToShorten.clear(); + } + } + finally { + a.finish(); + psiMigration.finish(); + } + } + + @Override + @RequiredReadAction + protected void performPsiSpoilingRefactoring() { + JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); + for (SmartPsiElementPointer pointer : myRefsToShorten) { + PsiElement element = pointer.getElement(); + if (element != null) { + styleManager.shortenClassReferences(element); + } + } + } + + @Override + @Nonnull + protected String getCommandName() { + return RefactoringLocalize.migrationTitle().get(); + } + + static class MigrationUsageInfo extends UsageInfo { + MigrationMapEntry mapEntry; + + @RequiredReadAction + MigrationUsageInfo(UsageInfo info, MigrationMapEntry mapEntry) { + super(info.getElement(), info.getRangeInElement().getStartOffset(), info.getRangeInElement().getEndOffset()); + this.mapEntry = mapEntry; + } + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveDirectoryWithClassesProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveDirectoryWithClassesProcessor.java index 48293dea6..192c28952 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveDirectoryWithClassesProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveDirectoryWithClassesProcessor.java @@ -39,260 +39,270 @@ import consulo.platform.base.localize.CommonLocalize; import consulo.project.DumbService; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.awt.Messages; import consulo.usage.NonCodeUsageInfo; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.usage.UsageViewUtil; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import java.util.*; public class MoveDirectoryWithClassesProcessor extends BaseRefactoringProcessor { - private final PsiDirectory[] myDirectories; - private final PsiDirectory myTargetDirectory; - private final boolean mySearchInComments; - private final boolean mySearchInNonJavaFiles; - private final Map myFilesToMove; - private NonCodeUsageInfo[] myNonCodeUsages; - private final MoveCallback myMoveCallback; + private final PsiDirectory[] myDirectories; + private final PsiDirectory myTargetDirectory; + private final boolean mySearchInComments; + private final boolean mySearchInNonJavaFiles; + private final Map myFilesToMove; + private NonCodeUsageInfo[] myNonCodeUsages; + private final MoveCallback myMoveCallback; - @RequiredReadAction - public MoveDirectoryWithClassesProcessor( - Project project, - PsiDirectory[] directories, - PsiDirectory targetDirectory, - boolean searchInComments, - boolean searchInNonJavaFiles, - boolean includeSelf, - MoveCallback moveCallback - ) { - super(project); - if (targetDirectory != null) { - final List dirs = new ArrayList<>(Arrays.asList(directories)); - for (Iterator iterator = dirs.iterator(); iterator.hasNext(); ) { - final PsiDirectory directory = iterator.next(); - if (targetDirectory.equals(directory.getParentDirectory()) || targetDirectory.equals(directory)) { - iterator.remove(); + @RequiredReadAction + public MoveDirectoryWithClassesProcessor( + Project project, + PsiDirectory[] directories, + PsiDirectory targetDirectory, + boolean searchInComments, + boolean searchInNonJavaFiles, + boolean includeSelf, + MoveCallback moveCallback + ) { + super(project); + if (targetDirectory != null) { + List dirs = new ArrayList<>(Arrays.asList(directories)); + for (Iterator iterator = dirs.iterator(); iterator.hasNext(); ) { + PsiDirectory directory = iterator.next(); + if (targetDirectory.equals(directory.getParentDirectory()) || targetDirectory.equals(directory)) { + iterator.remove(); + } + } + directories = dirs.toArray(new PsiDirectory[dirs.size()]); + } + myDirectories = directories; + myTargetDirectory = targetDirectory; + mySearchInComments = searchInComments; + mySearchInNonJavaFiles = searchInNonJavaFiles; + myMoveCallback = moveCallback; + myFilesToMove = new HashMap<>(); + for (PsiDirectory dir : directories) { + collectFiles2Move(myFilesToMove, dir, includeSelf ? dir.getParentDirectory() : dir, getTargetDirectory(dir)); } - } - directories = dirs.toArray(new PsiDirectory[dirs.size()]); - } - myDirectories = directories; - myTargetDirectory = targetDirectory; - mySearchInComments = searchInComments; - mySearchInNonJavaFiles = searchInNonJavaFiles; - myMoveCallback = moveCallback; - myFilesToMove = new HashMap<>(); - for (PsiDirectory dir : directories) { - collectFiles2Move(myFilesToMove, dir, includeSelf ? dir.getParentDirectory() : dir, getTargetDirectory(dir)); } - } - - @Nonnull - @Override - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - PsiElement[] elements = new PsiElement[myFilesToMove.size()]; - final PsiFile[] classes = PsiUtilCore.toPsiFileArray(myFilesToMove.keySet()); - System.arraycopy(classes, 0, elements, 0, classes.length); - return new MoveMultipleElementsViewDescriptor(elements, getTargetName()); - } - protected String getTargetName() { - return RefactoringUIUtil.getDescription(getTargetDirectory(null).getTargetDirectory(), false); - } - - @Nonnull - @Override - public UsageInfo[] findUsages() { - final List usages = new ArrayList<>(); - for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { - helper.findUsages(myFilesToMove.keySet(), myDirectories, usages, mySearchInComments, mySearchInNonJavaFiles, myProject); + @Nonnull + @Override + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + PsiElement[] elements = new PsiElement[myFilesToMove.size()]; + PsiFile[] classes = PsiUtilCore.toPsiFileArray(myFilesToMove.keySet()); + System.arraycopy(classes, 0, elements, 0, classes.length); + return new MoveMultipleElementsViewDescriptor(elements, getTargetName()); } - return UsageViewUtil.removeDuplicatedUsages(usages.toArray(new UsageInfo[usages.size()])); - } - @Override - protected boolean preprocessUsages(Ref refUsages) { - final MultiMap conflicts = new MultiMap<>(); - for (PsiFile psiFile : myFilesToMove.keySet()) { - try { - myFilesToMove.get(psiFile).checkMove(psiFile); - } catch (IncorrectOperationException e) { - conflicts.putValue(psiFile, e.getMessage()); - } - } - for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { - helper.preprocessUsages(myProject, myFilesToMove.keySet(), refUsages.get(), myTargetDirectory, conflicts); + protected String getTargetName() { + return RefactoringUIUtil.getDescription(getTargetDirectory(null).getTargetDirectory(), false); } - return showConflicts(conflicts, refUsages.get()); - } - @Override - protected void refreshElements(PsiElement[] elements) { - } - - @Override - public void performRefactoring(UsageInfo[] usages) { - //try to create all directories beforehand - try { - //top level directories should be created even if they are empty - for (PsiDirectory directory : myDirectories) { - getResultDirectory(directory).findOrCreateTargetDirectory(); - } - for (PsiFile psiFile : myFilesToMove.keySet()) { - myFilesToMove.get(psiFile).findOrCreateTargetDirectory(); - } - - DumbService.getInstance(myProject).completeJustSubmittedTasks(); - } catch (IncorrectOperationException e) { - Messages.showErrorDialog(myProject, e.getMessage(), CommonLocalize.titleError().get()); - return; - } - try { - final List movedFiles = new ArrayList<>(); - final Map oldToNewElementsMapping = new HashMap<>(); - for (PsiFile psiFile : myFilesToMove.keySet()) { + @Nonnull + @Override + public UsageInfo[] findUsages() { + List usages = new ArrayList<>(); for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { - helper.beforeMove(psiFile); + helper.findUsages(myFilesToMove.keySet(), myDirectories, usages, mySearchInComments, mySearchInNonJavaFiles, myProject); } - final RefactoringElementListener listener = getTransaction().getElementListener(psiFile); - final PsiDirectory moveDestination = myFilesToMove.get(psiFile).getTargetDirectory(); + return UsageViewUtil.removeDuplicatedUsages(usages.toArray(new UsageInfo[usages.size()])); + } - for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { - boolean processed = helper.move(psiFile, moveDestination, oldToNewElementsMapping, movedFiles, listener); - if (processed) { - break; - } + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + MultiMap conflicts = new MultiMap<>(); + for (PsiFile psiFile : myFilesToMove.keySet()) { + try { + myFilesToMove.get(psiFile).checkMove(psiFile); + } + catch (IncorrectOperationException e) { + conflicts.putValue(psiFile, e.getMessage()); + } } - } - for (PsiElement newElement : oldToNewElementsMapping.values()) { for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { - helper.afterMove(newElement); + helper.preprocessUsages(myProject, myFilesToMove.keySet(), refUsages.get(), myTargetDirectory, conflicts); } - } - - // fix references in moved files to outer files - for (PsiFile movedFile : movedFiles) { - MoveFileHandler.forElement(movedFile).updateMovedFile(movedFile); - FileReferenceContextUtil.decodeFileReferences(movedFile); - } + return showConflicts(conflicts, refUsages.get()); + } - myNonCodeUsages = CommonMoveUtil.retargetUsages(usages, oldToNewElementsMapping); - for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { - helper.postProcessUsages(usages, dir -> getResultDirectory(dir).getTargetDirectory()); - } - for (PsiDirectory directory : myDirectories) { - directory.delete(); - } - } catch (IncorrectOperationException e) { - myNonCodeUsages = new NonCodeUsageInfo[0]; - RefactoringUIUtil.processIncorrectOperation(myProject, e); + @Override + protected void refreshElements(@Nonnull PsiElement[] elements) { } - } - @RequiredReadAction - private TargetDirectoryWrapper getResultDirectory(PsiDirectory dir) { - return myTargetDirectory != null - ? new TargetDirectoryWrapper(myTargetDirectory, dir.getName()) - : getTargetDirectory(dir); - } + @Override + @RequiredUIAccess + public void performRefactoring(@Nonnull UsageInfo[] usages) { + //try to create all directories beforehand + try { + //top level directories should be created even if they are empty + for (PsiDirectory directory : myDirectories) { + getResultDirectory(directory).findOrCreateTargetDirectory(); + } + for (PsiFile psiFile : myFilesToMove.keySet()) { + myFilesToMove.get(psiFile).findOrCreateTargetDirectory(); + } - @Override - protected void performPsiSpoilingRefactoring() { - if (myNonCodeUsages == null) return; //refactoring was aborted - RenameUtil.renameNonCodeUsages(myProject, myNonCodeUsages); - if (myMoveCallback != null) { - myMoveCallback.refactoringCompleted(); - } - } + DumbService.getInstance(myProject).completeJustSubmittedTasks(); + } + catch (IncorrectOperationException e) { + Messages.showErrorDialog(myProject, e.getMessage(), CommonLocalize.titleError().get()); + return; + } + try { + List movedFiles = new ArrayList<>(); + Map oldToNewElementsMapping = new HashMap<>(); + for (PsiFile psiFile : myFilesToMove.keySet()) { + for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { + helper.beforeMove(psiFile); + } + RefactoringElementListener listener = getTransaction().getElementListener(psiFile); + PsiDirectory moveDestination = myFilesToMove.get(psiFile).getTargetDirectory(); + + for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { + boolean processed = helper.move(psiFile, moveDestination, oldToNewElementsMapping, movedFiles, listener); + if (processed) { + break; + } + } + } + for (PsiElement newElement : oldToNewElementsMapping.values()) { + for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { + helper.afterMove(newElement); + } + } - @RequiredReadAction - private static void collectFiles2Move( - Map files2Move, - PsiDirectory directory, - PsiDirectory rootDirectory, - @Nonnull TargetDirectoryWrapper targetDirectory - ) { - final PsiElement[] children = directory.getChildren(); - final String relativePath = VfsUtilCore.getRelativePath(directory.getVirtualFile(), rootDirectory.getVirtualFile(), '/'); + // fix references in moved files to outer files + for (PsiFile movedFile : movedFiles) { + MoveFileHandler.forElement(movedFile).updateMovedFile(movedFile); + FileReferenceContextUtil.decodeFileReferences(movedFile); + } - final TargetDirectoryWrapper newTargetDirectory = relativePath.isEmpty() - ? targetDirectory - : targetDirectory.findOrCreateChild(relativePath); - for (PsiElement child : children) { - if (child instanceof PsiFile file) { - files2Move.put(file, newTargetDirectory); - } else if (child instanceof PsiDirectory psiDirectory) { - collectFiles2Move(files2Move, psiDirectory, directory, newTargetDirectory); - } + myNonCodeUsages = CommonMoveUtil.retargetUsages(usages, oldToNewElementsMapping); + for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) { + helper.postProcessUsages(usages, dir -> getResultDirectory(dir).getTargetDirectory()); + } + for (PsiDirectory directory : myDirectories) { + directory.delete(); + } + } + catch (IncorrectOperationException e) { + myNonCodeUsages = new NonCodeUsageInfo[0]; + RefactoringUIUtil.processIncorrectOperation(myProject, e); + } } - } - @Override - protected String getCommandName() { - return RefactoringLocalize.movingDirectoriesCommand().get(); - } + @RequiredReadAction + private TargetDirectoryWrapper getResultDirectory(PsiDirectory dir) { + return myTargetDirectory != null + ? new TargetDirectoryWrapper(myTargetDirectory, dir.getName()) + : getTargetDirectory(dir); + } - public TargetDirectoryWrapper getTargetDirectory(PsiDirectory dir) { - return new TargetDirectoryWrapper(myTargetDirectory); - } + @Override + protected void performPsiSpoilingRefactoring() { + if (myNonCodeUsages == null) { + return; //refactoring was aborted + } + RenameUtil.renameNonCodeUsages(myProject, myNonCodeUsages); + if (myMoveCallback != null) { + myMoveCallback.refactoringCompleted(); + } + } - public static class TargetDirectoryWrapper { - private TargetDirectoryWrapper myParentDirectory; - private PsiDirectory myTargetDirectory; - private String myRelativePath; + @RequiredReadAction + private static void collectFiles2Move( + Map files2Move, + PsiDirectory directory, + PsiDirectory rootDirectory, + @Nonnull TargetDirectoryWrapper targetDirectory + ) { + PsiElement[] children = directory.getChildren(); + String relativePath = VfsUtilCore.getRelativePath(directory.getVirtualFile(), rootDirectory.getVirtualFile(), '/'); - public TargetDirectoryWrapper(PsiDirectory targetDirectory) { - myTargetDirectory = targetDirectory; + TargetDirectoryWrapper newTargetDirectory = relativePath.isEmpty() + ? targetDirectory + : targetDirectory.findOrCreateChild(relativePath); + for (PsiElement child : children) { + if (child instanceof PsiFile file) { + files2Move.put(file, newTargetDirectory); + } + else if (child instanceof PsiDirectory psiDirectory) { + collectFiles2Move(files2Move, psiDirectory, directory, newTargetDirectory); + } + } } - public TargetDirectoryWrapper(TargetDirectoryWrapper parentDirectory, String relativePath) { - myParentDirectory = parentDirectory; - myRelativePath = relativePath; + @Nonnull + @Override + protected String getCommandName() { + return RefactoringLocalize.movingDirectoriesCommand().get(); } - public TargetDirectoryWrapper(PsiDirectory parentDirectory, String relativePath) { - myTargetDirectory = parentDirectory.findSubdirectory(relativePath); - //in case it was null - myParentDirectory = new TargetDirectoryWrapper(parentDirectory); - myRelativePath = relativePath; + public TargetDirectoryWrapper getTargetDirectory(PsiDirectory dir) { + return new TargetDirectoryWrapper(myTargetDirectory); } - public PsiDirectory findOrCreateTargetDirectory() throws IncorrectOperationException { - if (myTargetDirectory == null) { - final PsiDirectory root = myParentDirectory.findOrCreateTargetDirectory(); + public static class TargetDirectoryWrapper { + private TargetDirectoryWrapper myParentDirectory; + private PsiDirectory myTargetDirectory; + private String myRelativePath; - myTargetDirectory = root.findSubdirectory(myRelativePath); - if (myTargetDirectory == null) { - myTargetDirectory = root.createSubdirectory(myRelativePath); + public TargetDirectoryWrapper(PsiDirectory targetDirectory) { + myTargetDirectory = targetDirectory; } - } - return myTargetDirectory; - } - @Nullable - public PsiDirectory getTargetDirectory() { - return myTargetDirectory; - } + public TargetDirectoryWrapper(TargetDirectoryWrapper parentDirectory, String relativePath) { + myParentDirectory = parentDirectory; + myRelativePath = relativePath; + } - public TargetDirectoryWrapper findOrCreateChild(String relativePath) { - if (myTargetDirectory != null) { - final PsiDirectory psiDirectory = myTargetDirectory.findSubdirectory(relativePath); - if (psiDirectory != null) { - return new TargetDirectoryWrapper(psiDirectory); + public TargetDirectoryWrapper(PsiDirectory parentDirectory, String relativePath) { + myTargetDirectory = parentDirectory.findSubdirectory(relativePath); + //in case it was null + myParentDirectory = new TargetDirectoryWrapper(parentDirectory); + myRelativePath = relativePath; } - } - return new TargetDirectoryWrapper(this, relativePath); - } - public void checkMove(PsiFile psiFile) throws IncorrectOperationException { - if (myTargetDirectory != null) { - MoveFilesOrDirectoriesUtil.checkMove(psiFile, myTargetDirectory); - } + public PsiDirectory findOrCreateTargetDirectory() throws IncorrectOperationException { + if (myTargetDirectory == null) { + PsiDirectory root = myParentDirectory.findOrCreateTargetDirectory(); + + myTargetDirectory = root.findSubdirectory(myRelativePath); + if (myTargetDirectory == null) { + myTargetDirectory = root.createSubdirectory(myRelativePath); + } + } + return myTargetDirectory; + } + + @Nullable + public PsiDirectory getTargetDirectory() { + return myTargetDirectory; + } + + public TargetDirectoryWrapper findOrCreateChild(String relativePath) { + if (myTargetDirectory != null) { + PsiDirectory psiDirectory = myTargetDirectory.findSubdirectory(relativePath); + if (psiDirectory != null) { + return new TargetDirectoryWrapper(psiDirectory); + } + } + return new TargetDirectoryWrapper(this, relativePath); + } + + public void checkMove(PsiFile psiFile) throws IncorrectOperationException { + if (myTargetDirectory != null) { + MoveFilesOrDirectoriesUtil.checkMove(psiFile, myTargetDirectory); + } + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/removemiddleman/RemoveMiddlemanProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/removemiddleman/RemoveMiddlemanProcessor.java index 82d0370cc..19ef41093 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/removemiddleman/RemoveMiddlemanProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/removemiddleman/RemoveMiddlemanProcessor.java @@ -21,7 +21,10 @@ import com.intellij.java.impl.refactoring.util.FixableUsageInfo; import com.intellij.java.impl.refactoring.util.FixableUsagesRefactoringProcessor; import com.intellij.java.impl.refactoring.util.classMembers.MemberInfo; -import com.intellij.java.language.psi.*; +import com.intellij.java.language.psi.PsiClass; +import com.intellij.java.language.psi.PsiField; +import com.intellij.java.language.psi.PsiMethod; +import com.intellij.java.language.psi.PsiMethodCallExpression; import com.intellij.java.language.psi.util.PropertyUtil; import consulo.annotation.access.RequiredReadAction; import consulo.java.localize.JavaRefactoringLocalize; @@ -35,7 +38,7 @@ import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.List; @@ -52,8 +55,8 @@ public RemoveMiddlemanProcessor(PsiField field, List memberInfos) { super(field.getProject()); this.field = field; containingClass = field.getContainingClass(); - final String propertyName = PropertyUtil.suggestPropertyName(field); - final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); + String propertyName = PropertyUtil.suggestPropertyName(field); + boolean isStatic = field.isStatic(); getter = PropertyUtil.findPropertyGetter(containingClass, propertyName, isStatic, false); myDelegateMethodInfos = memberInfos; } @@ -67,14 +70,14 @@ protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usa @Override @RequiredReadAction public void findUsages(@Nonnull List usages) { - for (final MemberInfo memberInfo : myDelegateMethodInfos) { + for (MemberInfo memberInfo : myDelegateMethodInfos) { if (!memberInfo.isChecked()) { continue; } - final PsiMethod method = (PsiMethod)memberInfo.getMember(); - final String getterName = PropertyUtil.suggestGetterName(field); - final int[] paramPermutation = DelegationUtils.getParameterPermutation(method); - final PsiMethod delegatedMethod = DelegationUtils.getDelegatedMethod(method); + PsiMethod method = (PsiMethod)memberInfo.getMember(); + String getterName = PropertyUtil.suggestGetterName(field); + int[] paramPermutation = DelegationUtils.getParameterPermutation(method); + PsiMethod delegatedMethod = DelegationUtils.getDelegatedMethod(method); LOG.assertTrue(!DelegationUtils.isAbstract(method)); processUsagesForMethod(memberInfo.isToAbstract(), method, paramPermutation, getterName, delegatedMethod, usages); } @@ -82,8 +85,8 @@ public void findUsages(@Nonnull List usages) { @Override @RequiredUIAccess - protected boolean preprocessUsages(@Nonnull final Ref refUsages) { - final MultiMap conflicts = new MultiMap<>(); + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + MultiMap conflicts = new MultiMap<>(); for (MemberInfo memberInfo : myDelegateMethodInfos) { if (memberInfo.isChecked() && memberInfo.isToAbstract() && memberInfo.getMember() instanceof PsiMethod method && method.findDeepestSuperMethods().length > 0) { @@ -100,7 +103,7 @@ protected boolean preprocessUsages(@Nonnull final Ref refUsages) { @RequiredReadAction private void processUsagesForMethod( - final boolean deleteMethodHierarchy, + boolean deleteMethodHierarchy, PsiMethod method, int[] paramPermutation, String getterName, @@ -128,7 +131,7 @@ private void processUsagesForMethod( } @Override - protected void performRefactoring(UsageInfo[] usageInfos) { + protected void performRefactoring(@Nonnull UsageInfo[] usageInfos) { if (getter != null) { try { if (containingClass.findMethodBySignature(getter, false) == null) { diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java index 951ee1b02..bc392d2b5 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java @@ -15,13 +15,13 @@ */ package com.intellij.java.impl.refactoring.replaceConstructorWithBuilder; +import com.intellij.java.impl.codeInsight.PackageUtil; import com.intellij.java.impl.refactoring.MoveDestination; import com.intellij.java.impl.refactoring.replaceConstructorWithBuilder.usageInfo.ReplaceConstructorWithSettersChainInfo; import com.intellij.java.impl.refactoring.util.FixableUsageInfo; import com.intellij.java.impl.refactoring.util.FixableUsagesRefactoringProcessor; import com.intellij.java.impl.refactoring.util.RefactoringUtil; import com.intellij.java.language.impl.JavaFileType; -import com.intellij.java.impl.codeInsight.PackageUtil; import com.intellij.java.language.psi.PsiElementFactory; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.codeStyle.JavaCodeStyleManager; @@ -30,6 +30,7 @@ import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.psi.util.TypeConversionUtil; import com.intellij.java.language.util.VisibilityUtil; +import consulo.annotation.access.RequiredReadAction; import consulo.ide.impl.idea.openapi.module.ModuleUtil; import consulo.language.codeStyle.CodeStyleManager; import consulo.language.psi.*; @@ -39,291 +40,312 @@ import consulo.language.util.IncorrectOperationException; import consulo.module.Module; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; import consulo.util.lang.Comparing; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; - import jakarta.annotation.Nullable; + import java.util.Collections; import java.util.List; import java.util.Map; /** * @author anna - * @since 04-Sep-2008 + * @since 2008-09-04 */ public class ReplaceConstructorWithBuilderProcessor extends FixableUsagesRefactoringProcessor { - public static final String REFACTORING_NAME = "Replace Constructor with Builder"; - private final PsiMethod[] myConstructors; - private final Map myParametersMap; - private final String myClassName; - private final String myPackageName; - private final boolean myCreateNewBuilderClass; - private final PsiElementFactory myElementFactory; - private MoveDestination myMoveDestination; - - - public ReplaceConstructorWithBuilderProcessor(Project project, - PsiMethod[] constructors, - Map parametersMap, - String className, - String packageName, - MoveDestination moveDestination, boolean createNewBuilderClass) { - super(project); - myMoveDestination = moveDestination; - myElementFactory = JavaPsiFacade.getInstance(myProject).getElementFactory(); - myConstructors = constructors; - myParametersMap = parametersMap; - - myClassName = className; - myPackageName = packageName; - myCreateNewBuilderClass = createNewBuilderClass; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(final UsageInfo[] usages) { - return new ReplaceConstructorWithBuilderViewDescriptor(); - } - - protected void findUsages(@Nonnull final List usages) { - final String builderQualifiedName = StringUtil.getQualifiedName(myPackageName, myClassName); - final PsiClass builderClass = - JavaPsiFacade.getInstance(myProject).findClass(builderQualifiedName, GlobalSearchScope.projectScope(myProject)); - - for (PsiMethod constructor : myConstructors) { - for (PsiReference reference : ReferencesSearch.search(constructor)) { - final PsiElement element = reference.getElement(); - final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class); - if (newExpression != null && !PsiTreeUtil.isAncestor(builderClass, element, false)) { - usages.add(new ReplaceConstructorWithSettersChainInfo(newExpression, StringUtil.getQualifiedName(myPackageName, myClassName), myParametersMap)); - } - } + public static final String REFACTORING_NAME = "Replace Constructor with Builder"; + private final PsiMethod[] myConstructors; + private final Map myParametersMap; + private final String myClassName; + private final String myPackageName; + private final boolean myCreateNewBuilderClass; + private final PsiElementFactory myElementFactory; + private MoveDestination myMoveDestination; + + + public ReplaceConstructorWithBuilderProcessor( + Project project, + PsiMethod[] constructors, + Map parametersMap, + String className, + String packageName, + MoveDestination moveDestination, boolean createNewBuilderClass + ) { + super(project); + myMoveDestination = moveDestination; + myElementFactory = JavaPsiFacade.getInstance(myProject).getElementFactory(); + myConstructors = constructors; + myParametersMap = parametersMap; + + myClassName = className; + myPackageName = packageName; + myCreateNewBuilderClass = createNewBuilderClass; + } + + @Nonnull + @Override + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull final UsageInfo[] usages) { + return new ReplaceConstructorWithBuilderViewDescriptor(); } - } - - @Nullable - private PsiClass createBuilderClass() { - final PsiClass psiClass = myConstructors[0].getContainingClass(); - assert psiClass != null; - final PsiTypeParameterList typeParameterList = psiClass.getTypeParameterList(); - final String text = "public class " + myClassName + (typeParameterList != null ? typeParameterList.getText() : "") + "{}"; - final PsiFileFactory factory = PsiFileFactory.getInstance(myProject); - final PsiJavaFile newFile = (PsiJavaFile) factory.createFileFromText(myClassName + ".java", JavaFileType.INSTANCE, text); - - final PsiFile containingFile = myConstructors[0].getContainingFile(); - final PsiDirectory containingDirectory = containingFile.getContainingDirectory(); - final PsiDirectory directory; - if (myMoveDestination != null) { - directory = myMoveDestination.getTargetDirectory(containingDirectory); - } else { - final Module module = ModuleUtil.findModuleForPsiElement(containingFile); - assert module != null; - directory = PackageUtil.findOrCreateDirectoryForPackage(module, myPackageName, containingDirectory, true, true); + + @Override + @RequiredReadAction + protected void findUsages(@Nonnull final List usages) { + final String builderQualifiedName = StringUtil.getQualifiedName(myPackageName, myClassName); + final PsiClass builderClass = + JavaPsiFacade.getInstance(myProject).findClass(builderQualifiedName, GlobalSearchScope.projectScope(myProject)); + + for (PsiMethod constructor : myConstructors) { + for (PsiReference reference : ReferencesSearch.search(constructor)) { + final PsiElement element = reference.getElement(); + final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class); + if (newExpression != null && !PsiTreeUtil.isAncestor(builderClass, element, false)) { + usages.add(new ReplaceConstructorWithSettersChainInfo( + newExpression, + StringUtil.getQualifiedName(myPackageName, myClassName), + myParametersMap + )); + } + } + } } - if (directory != null) { + @Nullable + @RequiredReadAction + private PsiClass createBuilderClass() { + final PsiClass psiClass = myConstructors[0].getContainingClass(); + assert psiClass != null; + final PsiTypeParameterList typeParameterList = psiClass.getTypeParameterList(); + final String text = "public class " + myClassName + (typeParameterList != null ? typeParameterList.getText() : "") + "{}"; + final PsiFileFactory factory = PsiFileFactory.getInstance(myProject); + final PsiJavaFile newFile = (PsiJavaFile)factory.createFileFromText(myClassName + ".java", JavaFileType.INSTANCE, text); + + final PsiFile containingFile = myConstructors[0].getContainingFile(); + final PsiDirectory containingDirectory = containingFile.getContainingDirectory(); + final PsiDirectory directory; + if (myMoveDestination != null) { + directory = myMoveDestination.getTargetDirectory(containingDirectory); + } + else { + final Module module = ModuleUtil.findModuleForPsiElement(containingFile); + assert module != null; + directory = PackageUtil.findOrCreateDirectoryForPackage(module, myPackageName, containingDirectory, true, true); + } - final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(PsiManager.getInstance(myProject).getProject()); - final PsiJavaFile reformattedFile = (PsiJavaFile) codeStyleManager.reformat(JavaCodeStyleManager.getInstance(newFile.getProject()).shortenClassReferences(newFile)); + if (directory != null) { - if (directory.findFile(reformattedFile.getName()) != null) return reformattedFile.getClasses()[0]; - return ((PsiJavaFile) directory.add(reformattedFile)).getClasses()[0]; - } - return null; - } - - @Override - protected void performRefactoring(UsageInfo[] usageInfos) { - - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); - final PsiClass builderClass = myCreateNewBuilderClass - ? createBuilderClass() - : psiFacade.findClass(StringUtil.getQualifiedName(myPackageName, myClassName), - GlobalSearchScope.projectScope(myProject)); - if (builderClass == null) return; - - for (String propertyName : myParametersMap.keySet()) { - final ParameterData parameterData = myParametersMap.get(propertyName); - final PsiField field = createField(builderClass, parameterData); - createSetter(builderClass, parameterData, field); + final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(PsiManager.getInstance(myProject).getProject()); + final PsiJavaFile reformattedFile = + (PsiJavaFile)codeStyleManager.reformat(JavaCodeStyleManager.getInstance(newFile.getProject()) + .shortenClassReferences(newFile)); + + if (directory.findFile(reformattedFile.getName()) != null) { + return reformattedFile.getClasses()[0]; + } + return ((PsiJavaFile)directory.add(reformattedFile)).getClasses()[0]; + } + return null; } - super.performRefactoring(usageInfos); + @Override + @RequiredReadAction + protected void performRefactoring(@Nonnull UsageInfo[] usageInfos) { + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); + final PsiClass builderClass = myCreateNewBuilderClass + ? createBuilderClass() + : psiFacade.findClass( + StringUtil.getQualifiedName(myPackageName, myClassName), + GlobalSearchScope.projectScope(myProject) + ); + if (builderClass == null) { + return; + } + + for (String propertyName : myParametersMap.keySet()) { + final ParameterData parameterData = myParametersMap.get(propertyName); + final PsiField field = createField(builderClass, parameterData); + createSetter(builderClass, parameterData, field); + } + + super.performRefactoring(usageInfos); - final PsiMethod method = createMethodSignature(createMethodName()); - if (builderClass.findMethodBySignature(method, false) == null) { - builderClass.add(method); + final PsiMethod method = createMethodSignature(createMethodName()); + if (builderClass.findMethodBySignature(method, false) == null) { + builderClass.add(method); + } + + //fix visibilities + final PsiMethod constructor = getWorkingConstructor(); + VisibilityUtil.escalateVisibility(constructor, builderClass); + PsiClass containingClass = constructor.getContainingClass(); + while (containingClass != null) { + VisibilityUtil.escalateVisibility(containingClass, builderClass); + containingClass = containingClass.getContainingClass(); + } } - //fix visibilities - final PsiMethod constructor = getWorkingConstructor(); - VisibilityUtil.escalateVisibility(constructor, builderClass); - PsiClass containingClass = constructor.getContainingClass(); - while (containingClass != null) { - VisibilityUtil.escalateVisibility(containingClass, builderClass); - containingClass = containingClass.getContainingClass(); + private void createSetter(PsiClass builderClass, ParameterData parameterData, PsiField field) { + PsiMethod setter = null; + for (PsiMethod method : builderClass.getMethods()) { + if (Comparing.strEqual(method.getName(), parameterData.getSetterName()) && method.getParameterList().getParametersCount() == 1 + && TypeConversionUtil.isAssignable(method.getParameterList().getParameters()[0].getType(), parameterData.getType())) { + setter = method; + fixSetterReturnType(builderClass, field, setter); + break; + } + } + if (setter == null) { + setter = PropertyUtil.generateSetterPrototype(field, builderClass, true); + final PsiIdentifier nameIdentifier = setter.getNameIdentifier(); + assert nameIdentifier != null; + nameIdentifier.replace(myElementFactory.createIdentifier(parameterData.getSetterName())); + setter.getParameterList().getParameters()[0].getTypeElement() + .replace(myElementFactory.createTypeElement(parameterData.getType())); //setter varargs + builderClass.add(setter); + } } - } - - private void createSetter(PsiClass builderClass, ParameterData parameterData, PsiField field) { - PsiMethod setter = null; - for (PsiMethod method : builderClass.getMethods()) { - if (Comparing.strEqual(method.getName(), parameterData.getSetterName()) && method.getParameterList().getParametersCount() == 1 - && TypeConversionUtil.isAssignable(method.getParameterList().getParameters()[0].getType(), parameterData.getType())) { - setter = method; - fixSetterReturnType(builderClass, field, setter); - break; - } + + private PsiField createField(PsiClass builderClass, ParameterData parameterData) { + PsiField field = builderClass.findFieldByName(parameterData.getFieldName(), false); + + if (field == null) { + PsiType type = parameterData.getType(); + if (type instanceof PsiEllipsisType) { + type = ((PsiEllipsisType)type).toArrayType(); + } + field = myElementFactory.createField(parameterData.getFieldName(), type); + field = (PsiField)builderClass.add(field); + } + + final String defaultValue = parameterData.getDefaultValue(); + if (defaultValue != null) { + final PsiExpression initializer = field.getInitializer(); + if (initializer == null) { + try { + field.setInitializer(myElementFactory.createExpressionFromText(defaultValue, field)); + } + catch (IncorrectOperationException e) { + //skip invalid default value + } + } + } + return field; } - if (setter == null) { - setter = PropertyUtil.generateSetterPrototype(field, builderClass, true); - final PsiIdentifier nameIdentifier = setter.getNameIdentifier(); - assert nameIdentifier != null; - nameIdentifier.replace(myElementFactory.createIdentifier(parameterData.getSetterName())); - setter.getParameterList().getParameters()[0].getTypeElement().replace(myElementFactory.createTypeElement(parameterData.getType())); //setter varargs - builderClass.add(setter); + + private void fixSetterReturnType(PsiClass builderClass, PsiField field, PsiMethod method) { + if (PsiUtil.resolveClassInType(method.getReturnType()) != builderClass) { + final PsiCodeBlock body = method.getBody(); + final PsiCodeBlock generatedBody = PropertyUtil.generateSetterPrototype(field, builderClass, true).getBody(); + assert body != null; + assert generatedBody != null; + body.replace(generatedBody); + final PsiTypeElement typeElement = method.getReturnTypeElement(); + assert typeElement != null; + typeElement.replace(myElementFactory.createTypeElement(myElementFactory.createType(builderClass))); + } } - } - - private PsiField createField(PsiClass builderClass, ParameterData parameterData) { - PsiField field = builderClass.findFieldByName(parameterData.getFieldName(), false); - - if (field == null) { - PsiType type = parameterData.getType(); - if (type instanceof PsiEllipsisType) { - type = ((PsiEllipsisType) type).toArrayType(); - } - field = myElementFactory.createField(parameterData.getFieldName(), type); - field = (PsiField) builderClass.add(field); + + private PsiMethod createMethodSignature(String createMethodName) { + JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); + final StringBuilder buf = new StringBuilder(); + final PsiMethod constructor = getWorkingConstructor(); + for (PsiParameter parameter : constructor.getParameterList().getParameters()) { + final String pureParamName = styleManager.variableNameToPropertyName(parameter.getName(), VariableKind.PARAMETER); + if (buf.length() > 0) { + buf.append(", "); + } + buf.append(myParametersMap.get(pureParamName).getFieldName()); + } + return myElementFactory.createMethodFromText( + "public " + constructor.getName() + " " + createMethodName + "(){\n" + + " return new " + constructor.getName() + "(" + buf.toString() + ");\n" + + "}", + constructor + ); } - final String defaultValue = parameterData.getDefaultValue(); - if (defaultValue != null) { - final PsiExpression initializer = field.getInitializer(); - if (initializer == null) { - try { - field.setInitializer(myElementFactory.createExpressionFromText(defaultValue, field)); - } catch (IncorrectOperationException e) { - //skip invalid default value + private PsiMethod getWorkingConstructor() { + PsiMethod constructor = getMostCommonConstructor(); + if (constructor == null) { + constructor = myConstructors[0]; + if (constructor.getParameterList().getParametersCount() == 0) { + constructor = myConstructors[1]; + } } - } + return constructor; } - return field; - } - - private void fixSetterReturnType(PsiClass builderClass, PsiField field, PsiMethod method) { - if (PsiUtil.resolveClassInType(method.getReturnType()) != builderClass) { - final PsiCodeBlock body = method.getBody(); - final PsiCodeBlock generatedBody = PropertyUtil.generateSetterPrototype(field, builderClass, true).getBody(); - assert body != null; - assert generatedBody != null; - body.replace(generatedBody); - final PsiTypeElement typeElement = method.getReturnTypeElement(); - assert typeElement != null; - typeElement.replace(myElementFactory.createTypeElement(myElementFactory.createType(builderClass))); + + @Nullable + private PsiMethod getMostCommonConstructor() { + if (myConstructors.length == 1) { + return myConstructors[0]; + } + PsiMethod commonConstructor = null; + for (PsiMethod constructor : myConstructors) { + final PsiMethod chainedConstructor = RefactoringUtil.getChainedConstructor(constructor); + if (chainedConstructor == null) { + if (commonConstructor != null) { + if (!isChained(commonConstructor, constructor)) { + return null; + } + } + commonConstructor = constructor; + } + else if (commonConstructor == null) { + commonConstructor = chainedConstructor; + } + else if (!isChained(commonConstructor, chainedConstructor)) { + return null; + } + } + return commonConstructor; } - } - - private PsiMethod createMethodSignature(String createMethodName) { - JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); - final StringBuffer buf = new StringBuffer(); - final PsiMethod constructor = getWorkingConstructor(); - for (PsiParameter parameter : constructor.getParameterList().getParameters()) { - final String pureParamName = styleManager.variableNameToPropertyName(parameter.getName(), VariableKind.PARAMETER); - if (buf.length() > 0) buf.append(", "); - buf.append(myParametersMap.get(pureParamName).getFieldName()); + + private static boolean isChained(PsiMethod first, PsiMethod last) { + return first != null && (first == last || isChained(RefactoringUtil.getChainedConstructor(first), last)); } - return myElementFactory.createMethodFromText("public " + - constructor.getName() + - " " + - createMethodName + - "(){\n return new " + - constructor.getName() + - "(" + - buf.toString() + - ")" + - ";\n}", constructor); - } - - private PsiMethod getWorkingConstructor() { - PsiMethod constructor = getMostCommonConstructor(); - if (constructor == null) { - constructor = myConstructors[0]; - if (constructor.getParameterList().getParametersCount() == 0) { - constructor = myConstructors[1]; - } + + private String createMethodName() { + return "create" + StringUtil.capitalize(myConstructors[0].getName()); } - return constructor; - } - - @Nullable - private PsiMethod getMostCommonConstructor() { - if (myConstructors.length == 1) return myConstructors[0]; - PsiMethod commonConstructor = null; - for (PsiMethod constructor : myConstructors) { - final PsiMethod chainedConstructor = RefactoringUtil.getChainedConstructor(constructor); - if (chainedConstructor == null) { - if (commonConstructor != null) { - if (!isChained(commonConstructor, constructor)) { - return null; - } + + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + final MultiMap conflicts = new MultiMap<>(); + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); + final PsiClass builderClass = + psiFacade.findClass(StringUtil.getQualifiedName(myPackageName, myClassName), GlobalSearchScope.projectScope(myProject)); + if (builderClass == null) { + if (!myCreateNewBuilderClass) { + conflicts.putValue(null, "Selected class was not found."); + } + } + else if (myCreateNewBuilderClass) { + conflicts.putValue(builderClass, "Class with chosen name already exist."); + } + + if (myMoveDestination != null && myCreateNewBuilderClass) { + myMoveDestination.analyzeModuleConflicts(Collections.emptyList(), conflicts, refUsages.get()); } - commonConstructor = constructor; - } else { + + final PsiMethod commonConstructor = getMostCommonConstructor(); if (commonConstructor == null) { - commonConstructor = chainedConstructor; - } else { - if (!isChained(commonConstructor, chainedConstructor)) { - return null; - } + conflicts.putValue(null, "Found constructors are not reducible to simple chain"); } - } - } - return commonConstructor; - } - - private static boolean isChained(PsiMethod first, PsiMethod last) { - if (first == null) return false; - if (first == last) return true; - return isChained(RefactoringUtil.getChainedConstructor(first), last); - } - - private String createMethodName() { - return "create" + StringUtil.capitalize(myConstructors[0].getName()); - } - - - @Override - protected boolean preprocessUsages(Ref refUsages) { - final MultiMap conflicts = new MultiMap(); - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); - final PsiClass builderClass = - psiFacade.findClass(StringUtil.getQualifiedName(myPackageName, myClassName), GlobalSearchScope.projectScope(myProject)); - if (builderClass == null) { - if (!myCreateNewBuilderClass) { - conflicts.putValue(null, "Selected class was not found."); - } - } else if (myCreateNewBuilderClass) { - conflicts.putValue(builderClass, "Class with chosen name already exist."); - } - if (myMoveDestination != null && myCreateNewBuilderClass) { - myMoveDestination.analyzeModuleConflicts(Collections.emptyList(), conflicts, refUsages.get()); + return showConflicts(conflicts, refUsages.get()); } - final PsiMethod commonConstructor = getMostCommonConstructor(); - if (commonConstructor == null) { - conflicts.putValue(null, "Found constructors are not reducible to simple chain"); + @Override + protected String getCommandName() { + return REFACTORING_NAME; } - - return showConflicts(conflicts, refUsages.get()); - } - - protected String getCommandName() { - return REFACTORING_NAME; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/typeMigration/TypeMigrationProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/typeMigration/TypeMigrationProcessor.java index 984de2ed7..1855c39a9 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/typeMigration/TypeMigrationProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/typeMigration/TypeMigrationProcessor.java @@ -21,7 +21,8 @@ import com.intellij.java.impl.refactoring.util.RefactoringUtil; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.codeStyle.JavaCodeStyleManager; -import consulo.application.ApplicationManager; +import consulo.annotation.access.RequiredReadAction; +import consulo.application.Application; import consulo.codeEditor.Editor; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.psi.*; @@ -29,6 +30,7 @@ import consulo.project.Project; import consulo.project.ui.wm.ToolWindowId; import consulo.project.ui.wm.ToolWindowManager; +import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.content.Content; import consulo.usage.UsageInfo; import consulo.usage.UsageViewContentManager; @@ -37,7 +39,7 @@ import consulo.util.collection.SmartList; import consulo.util.lang.StringUtil; import consulo.util.lang.function.Functions; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.*; @@ -46,243 +48,286 @@ import static consulo.util.lang.ObjectUtil.assertNotNull; public class TypeMigrationProcessor extends BaseRefactoringProcessor { - public volatile static boolean ourSkipFailedConversionInTestMode; - private final static int MAX_ROOT_IN_PREVIEW_PRESENTATION = 3; + public volatile static boolean ourSkipFailedConversionInTestMode; + private final static int MAX_ROOT_IN_PREVIEW_PRESENTATION = 3; - private PsiElement[] myRoots; - private final Function myRootTypes; - private final boolean myAllowDependentRoots; - private final TypeMigrationRules myRules; - private TypeMigrationLabeler myLabeler; + private PsiElement[] myRoots; + private final Function myRootTypes; + private final boolean myAllowDependentRoots; + private final TypeMigrationRules myRules; + private TypeMigrationLabeler myLabeler; - public TypeMigrationProcessor(final Project project, final PsiElement[] roots, final Function rootTypes, final TypeMigrationRules rules, final boolean allowDependentRoots) { - super(project); - myRoots = roots; - myRules = rules; - myRootTypes = rootTypes; - myAllowDependentRoots = allowDependentRoots; - } + public TypeMigrationProcessor( + Project project, + PsiElement[] roots, + Function rootTypes, + TypeMigrationRules rules, + boolean allowDependentRoots + ) { + super(project); + myRoots = roots; + myRules = rules; + myRootTypes = rootTypes; + myAllowDependentRoots = allowDependentRoots; + } - public static void runHighlightingTypeMigration(final Project project, final Editor editor, final TypeMigrationRules rules, final PsiElement root, final PsiType migrationType) { - runHighlightingTypeMigration(project, editor, rules, root, migrationType, false, true); - } + @RequiredUIAccess + public static void runHighlightingTypeMigration( + Project project, + Editor editor, + TypeMigrationRules rules, + PsiElement root, + PsiType migrationType + ) { + runHighlightingTypeMigration(project, editor, rules, root, migrationType, false, true); + } - public static void runHighlightingTypeMigration(final Project project, - final Editor editor, - final TypeMigrationRules rules, - final PsiElement root, - final PsiType migrationType, - final boolean optimizeImports, - boolean allowDependentRoots) { - runHighlightingTypeMigration(project, editor, rules, new PsiElement[]{root}, Functions.constant(migrationType), optimizeImports, allowDependentRoots); - } + @RequiredUIAccess + public static void runHighlightingTypeMigration( + Project project, + Editor editor, + TypeMigrationRules rules, + PsiElement root, + PsiType migrationType, + boolean optimizeImports, + boolean allowDependentRoots + ) { + runHighlightingTypeMigration( + project, + editor, + rules, + new PsiElement[]{root}, + Functions.constant(migrationType), + optimizeImports, + allowDependentRoots + ); + } + @RequiredUIAccess + public static void runHighlightingTypeMigration( + Project project, + Editor editor, + TypeMigrationRules rules, + PsiElement[] roots, + Function migrationTypeFunction, + boolean optimizeImports, + boolean allowDependentRoots + ) { + Set containingFiles = ContainerUtil.map2Set(roots, PsiElement::getContainingFile); + TypeMigrationProcessor processor = + new TypeMigrationProcessor(project, roots, migrationTypeFunction, rules, allowDependentRoots) { + @Override + public void performRefactoring(@Nonnull UsageInfo[] usages) { + super.performRefactoring(usages); + if (editor != null) { + Application.get().invokeLater(() -> { + List result = new ArrayList<>(); + for (UsageInfo usage : usages) { + PsiElement element = usage.getElement(); + if (element == null || !containingFiles.contains(element.getContainingFile())) { + continue; + } + if (element instanceof PsiMethod method) { + result.add(method.getReturnTypeElement()); + } + else if (element instanceof PsiVariable variable) { + result.add(variable.getTypeElement()); + } + else { + result.add(element); + } + } + RefactoringUtil.highlightAllOccurrences(project, PsiUtilCore.toPsiElementArray(result), editor); + }); + } + if (optimizeImports) { + JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(myProject); + Set affectedFiles = new HashSet<>(); + for (UsageInfo usage : usages) { + PsiFile usageFile = usage.getFile(); + if (usageFile != null) { + affectedFiles.add(usageFile); + } + } + for (PsiFile file : affectedFiles) { + javaCodeStyleManager.optimizeImports(file); + javaCodeStyleManager.shortenClassReferences(file); + } + } + } + }; + processor.run(); + } - public static void runHighlightingTypeMigration(final Project project, - final Editor editor, - final TypeMigrationRules rules, - final PsiElement[] roots, - final Function migrationTypeFunction, - final boolean optimizeImports, - boolean allowDependentRoots) { - final Set containingFiles = ContainerUtil.map2Set(roots, PsiElement::getContainingFile); - final TypeMigrationProcessor processor = new TypeMigrationProcessor(project, roots, migrationTypeFunction, rules, allowDependentRoots) { - @Override - public void performRefactoring(@Nonnull final UsageInfo[] usages) { - super.performRefactoring(usages); - if (editor != null) { - ApplicationManager.getApplication().invokeLater(() -> - { - final List result = new ArrayList<>(); - for (UsageInfo usage : usages) { - final PsiElement element = usage.getElement(); - if (element == null || !containingFiles.contains(element.getContainingFile())) { - continue; - } - if (element instanceof PsiMethod) { - result.add(((PsiMethod) element).getReturnTypeElement()); - } else if (element instanceof PsiVariable) { - result.add(((PsiVariable) element).getTypeElement()); - } else { - result.add(element); - } + + @Nonnull + @Override + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new TypeMigrationViewDescriptor(myRoots[0]); + } + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + if (hasFailedConversions()) { + if (Application.get().isUnitTestMode()) { + if (ourSkipFailedConversionInTestMode) { + prepareSuccessful(); + return true; + } + throw new BaseRefactoringProcessor.ConflictsInTestsException(Arrays.asList(myLabeler.getFailedConversionsReport())); } - RefactoringUtil.highlightAllOccurrences(project, PsiUtilCore.toPsiElementArray(result), editor); - }); - } - if (optimizeImports) { - final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(myProject); - final Set affectedFiles = new HashSet<>(); - for (UsageInfo usage : usages) { - final PsiFile usageFile = usage.getFile(); - if (usageFile != null) { - affectedFiles.add(usageFile); + FailedConversionsDialog dialog = new FailedConversionsDialog(myLabeler.getFailedConversionsReport(), myProject); + if (!dialog.showAndGet()) { + int exitCode = dialog.getExitCode(); + prepareSuccessful(); + if (exitCode == FailedConversionsDialog.VIEW_USAGES_EXIT_CODE) { + previewRefactoring(refUsages.get()); + } + return false; } - } - for (PsiFile file : affectedFiles) { - javaCodeStyleManager.optimizeImports(file); - javaCodeStyleManager.shortenClassReferences(file); - } } - } - }; - processor.run(); - } + prepareSuccessful(); + return true; + } + public boolean hasFailedConversions() { + return myLabeler.hasFailedConversions(); + } - @Nonnull - @Override - protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { - return new TypeMigrationViewDescriptor(myRoots[0]); - } + @Override + @RequiredUIAccess + protected void previewRefactoring(@Nonnull UsageInfo[] usages) { + MigrationPanel panel = new MigrationPanel(myRoots, myLabeler, myProject, isPreviewUsages()); + String name; + if (myRoots.length == 1) { + String fromType = assertNotNull(TypeMigrationLabeler.getElementType(myRoots[0])).getPresentableText(); + String toType = myRootTypes.apply(myRoots[0]).getPresentableText(); + String text; + text = getPresentation(myRoots[0]); + name = "Migrate Type of " + text + " from \'" + fromType + "\' to \'" + toType + "\'"; + } + else { + int rootsInPresentationCount = + myRoots.length > MAX_ROOT_IN_PREVIEW_PRESENTATION ? MAX_ROOT_IN_PREVIEW_PRESENTATION : myRoots.length; + String[] rootsPresentation = new String[rootsInPresentationCount]; + for (int i = 0; i < rootsInPresentationCount; i++) { + PsiElement root = myRoots[i]; + rootsPresentation[i] = root instanceof PsiNamedElement namedElement ? namedElement.getName() : root.getText(); + } + rootsPresentation = StringUtil.surround(rootsPresentation, "\'", "\'"); + name = "Migrate Type of " + StringUtil.join(rootsPresentation, ", "); + if (myRoots.length > MAX_ROOT_IN_PREVIEW_PRESENTATION) { + name += "..."; + } + } + Content content = UsageViewContentManager.getInstance(myProject).addContent(name, false, panel, true, true); + panel.setContent(content); + ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND).activate(null); + } - @Override - protected boolean preprocessUsages(@Nonnull Ref refUsages) { - if (hasFailedConversions()) { - if (ApplicationManager.getApplication().isUnitTestMode()) { - if (ourSkipFailedConversionInTestMode) { - prepareSuccessful(); - return true; + @RequiredReadAction + public static String getPresentation(PsiElement element) { + if (element instanceof PsiField field) { + return "field \'" + field.getName() + "\'"; } - throw new BaseRefactoringProcessor.ConflictsInTestsException(Arrays.asList(myLabeler.getFailedConversionsReport())); - } - FailedConversionsDialog dialog = new FailedConversionsDialog(myLabeler.getFailedConversionsReport(), myProject); - if (!dialog.showAndGet()) { - final int exitCode = dialog.getExitCode(); - prepareSuccessful(); - if (exitCode == FailedConversionsDialog.VIEW_USAGES_EXIT_CODE) { - previewRefactoring(refUsages.get()); + else if (element instanceof PsiParameter parameter) { + return "parameter \'" + parameter.getName() + "\'"; + } + else if (element instanceof PsiLocalVariable localVar) { + return "variable \'" + localVar.getName() + "\'"; + } + else if (element instanceof PsiMethod method) { + return "method \'" + method.getName() + "\' return"; + } + else { + return element.getText(); } - return false; - } } - prepareSuccessful(); - return true; - } - public boolean hasFailedConversions() { - return myLabeler.hasFailedConversions(); - } + @Nonnull + @Override + @RequiredUIAccess + public UsageInfo[] findUsages() { + myLabeler = new TypeMigrationLabeler(myRules, myRootTypes, myAllowDependentRoots ? null : myRoots, myProject); - @Override - protected void previewRefactoring(@Nonnull final UsageInfo[] usages) { - MigrationPanel panel = new MigrationPanel(myRoots, myLabeler, myProject, isPreviewUsages()); - String name; - if (myRoots.length == 1) { - String fromType = assertNotNull(TypeMigrationLabeler.getElementType(myRoots[0])).getPresentableText(); - String toType = myRootTypes.apply(myRoots[0]).getPresentableText(); - String text; - text = getPresentation(myRoots[0]); - name = "Migrate Type of " + text + " from \'" + fromType + "\' to \'" + toType + "\'"; - } else { - final int rootsInPresentationCount = myRoots.length > MAX_ROOT_IN_PREVIEW_PRESENTATION ? MAX_ROOT_IN_PREVIEW_PRESENTATION : myRoots.length; - String[] rootsPresentation = new String[rootsInPresentationCount]; - for (int i = 0; i < rootsInPresentationCount; i++) { - final PsiElement root = myRoots[i]; - rootsPresentation[i] = root instanceof PsiNamedElement ? ((PsiNamedElement) root).getName() : root.getText(); - } - rootsPresentation = StringUtil.surround(rootsPresentation, "\'", "\'"); - name = "Migrate Type of " + StringUtil.join(rootsPresentation, ", "); - if (myRoots.length > MAX_ROOT_IN_PREVIEW_PRESENTATION) { - name += "..."; - } + try { + return myLabeler.getMigratedUsages(!isPreviewUsages(), myRoots); + } + catch (TypeMigrationLabeler.MigrateException e) { + setPreviewUsages(true); + myLabeler.clearStopException(); + return myLabeler.getMigratedUsages(false, myRoots); + } } - Content content = UsageViewContentManager.getInstance(myProject).addContent(name, false, panel, true, true); - panel.setContent(content); - ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND).activate(null); - } - public static String getPresentation(PsiElement element) { - String text; - if (element instanceof PsiField) { - text = "field \'" + ((PsiField) element).getName() + "\'"; - } else if (element instanceof PsiParameter) { - text = "parameter \'" + ((PsiParameter) element).getName() + "\'"; - } else if (element instanceof PsiLocalVariable) { - text = "variable \'" + ((PsiLocalVariable) element).getName() + "\'"; - } else if (element instanceof PsiMethod) { - text = "method \'" + ((PsiMethod) element).getName() + "\' return"; - } else { - text = element.getText(); + @Override + protected void refreshElements(@Nonnull PsiElement[] elements) { + myRoots = elements; } - return text; - } - @Nonnull - @Override - public UsageInfo[] findUsages() { - myLabeler = new TypeMigrationLabeler(myRules, myRootTypes, myAllowDependentRoots ? null : myRoots, myProject); - - try { - return myLabeler.getMigratedUsages(!isPreviewUsages(), myRoots); - } catch (TypeMigrationLabeler.MigrateException e) { - setPreviewUsages(true); - myLabeler.clearStopException(); - return myLabeler.getMigratedUsages(false, myRoots); + @Override + public void performRefactoring(@Nonnull UsageInfo[] usages) { + change(usages, myLabeler, myProject); } - } - - @Override - protected void refreshElements(@Nonnull PsiElement[] elements) { - myRoots = elements; - } - @Override - public void performRefactoring(@Nonnull UsageInfo[] usages) { - change(usages, myLabeler, myProject); - } + public static void change(UsageInfo[] usages, TypeMigrationLabeler labeler, Project project) { + List> newExpressionsToCheckDiamonds = new SmartList<>(); + TypeMigrationLabeler.MigrationProducer producer = labeler.createMigratorFor(usages); - public static void change(UsageInfo[] usages, TypeMigrationLabeler labeler, Project project) { - final List> newExpressionsToCheckDiamonds = new SmartList<>(); - final TypeMigrationLabeler.MigrationProducer producer = labeler.createMigratorFor(usages); - - final SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project); - List nonCodeUsages = new ArrayList<>(); - for (UsageInfo usage : usages) { - if (((TypeMigrationUsageInfo) usage).isExcluded()) { - continue; - } - final PsiElement element = usage.getElement(); - if (element instanceof PsiVariable || element instanceof PsiMember || element instanceof PsiExpression || element instanceof PsiReferenceParameterList) { - producer.change((TypeMigrationUsageInfo) usage, expression -> newExpressionsToCheckDiamonds.add(smartPointerManager.createSmartPsiElementPointer(expression))); - } else { - nonCodeUsages.add(usage); - } - } + SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project); + List nonCodeUsages = new ArrayList<>(); + for (UsageInfo usage : usages) { + if (((TypeMigrationUsageInfo)usage).isExcluded()) { + continue; + } + PsiElement element = usage.getElement(); + if (element instanceof PsiVariable || element instanceof PsiMember + || element instanceof PsiExpression || element instanceof PsiReferenceParameterList) { + producer.change( + (TypeMigrationUsageInfo)usage, + expression -> newExpressionsToCheckDiamonds.add(smartPointerManager.createSmartPsiElementPointer(expression)) + ); + } + else { + nonCodeUsages.add(usage); + } + } - for (SmartPsiElementPointer newExpressionPointer : newExpressionsToCheckDiamonds) { - final PsiNewExpression newExpression = newExpressionPointer.getElement(); - if (newExpression != null) { - labeler.postProcessNewExpression(newExpression); - } - } + for (SmartPsiElementPointer newExpressionPointer : newExpressionsToCheckDiamonds) { + PsiNewExpression newExpression = newExpressionPointer.getElement(); + if (newExpression != null) { + labeler.postProcessNewExpression(newExpression); + } + } - for (UsageInfo usageInfo : nonCodeUsages) { - final PsiElement element = usageInfo.getElement(); - if (element != null) { - final PsiReference reference = element.getReference(); - if (reference != null) { - final Object target = producer.getConversion(usageInfo); - if (target instanceof PsiMember) { - try { - reference.bindToElement((PsiElement) target); - } catch (IncorrectOperationException ignored) { + for (UsageInfo usageInfo : nonCodeUsages) { + PsiElement element = usageInfo.getElement(); + if (element != null) { + PsiReference reference = element.getReference(); + if (reference != null) { + Object target = producer.getConversion(usageInfo); + if (target instanceof PsiMember member) { + try { + reference.bindToElement(member); + } + catch (IncorrectOperationException ignored) { + } + } + } } - } } - } - } - producer.flush(); - } + producer.flush(); + } - public TypeMigrationLabeler getLabeler() { - return myLabeler; - } + public TypeMigrationLabeler getLabeler() { + return myLabeler; + } - @Nonnull - @Override - protected String getCommandName() { - return "TypeMigration"; - } + @Nonnull + @Override + protected String getCommandName() { + return "TypeMigration"; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/util/FixableUsagesRefactoringProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/util/FixableUsagesRefactoringProcessor.java index 89617d60d..3fa91c9be 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/util/FixableUsagesRefactoringProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/util/FixableUsagesRefactoringProcessor.java @@ -15,60 +15,62 @@ */ package com.intellij.java.impl.refactoring.util; -import consulo.project.Project; -import consulo.util.lang.ref.Ref; -import consulo.language.psi.PsiElement; +import com.intellij.xml.util.XmlUtil; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; -import consulo.usage.UsageInfo; +import consulo.language.psi.PsiElement; import consulo.language.util.IncorrectOperationException; -import consulo.util.collection.MultiMap; -import com.intellij.xml.util.XmlUtil; import consulo.logging.Logger; - +import consulo.project.Project; +import consulo.usage.UsageInfo; +import consulo.util.collection.MultiMap; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; + import java.util.ArrayList; import java.util.Collections; import java.util.List; public abstract class FixableUsagesRefactoringProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(FixableUsagesRefactoringProcessor.class); + private static final Logger LOG = Logger.getInstance(FixableUsagesRefactoringProcessor.class); - protected FixableUsagesRefactoringProcessor(Project project) { - super(project); - } + protected FixableUsagesRefactoringProcessor(Project project) { + super(project); + } - protected void performRefactoring(UsageInfo[] usageInfos) { - CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usageInfos); - for (UsageInfo usageInfo : usageInfos) { - if (usageInfo instanceof FixableUsageInfo) { - try { - ((FixableUsageInfo) usageInfo).fixUsage(); - } catch (IncorrectOperationException e) { - LOG.info(e); + @Override + protected void performRefactoring(@Nonnull UsageInfo[] usageInfos) { + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usageInfos); + for (UsageInfo usageInfo : usageInfos) { + if (usageInfo instanceof FixableUsageInfo) { + try { + ((FixableUsageInfo)usageInfo).fixUsage(); + } + catch (IncorrectOperationException e) { + LOG.info(e); + } + } } - } } - } - - @Nonnull - protected final UsageInfo[] findUsages() { - final List usages = Collections.synchronizedList(new ArrayList()); - findUsages(usages); - final int numUsages = usages.size(); - final FixableUsageInfo[] usageArray = usages.toArray(new FixableUsageInfo[numUsages]); - return usageArray; - } + @Nonnull + @Override + protected final UsageInfo[] findUsages() { + List usages = Collections.synchronizedList(new ArrayList()); + findUsages(usages); + final int numUsages = usages.size(); + final FixableUsageInfo[] usageArray = usages.toArray(new FixableUsageInfo[numUsages]); + return usageArray; + } - protected abstract void findUsages(@Nonnull List usages); + protected abstract void findUsages(@Nonnull List usages); - protected static void checkConflicts(final Ref refUsages, final MultiMap conflicts) { - for (UsageInfo info : refUsages.get()) { - final String conflict = ((FixableUsageInfo) info).getConflictMessage(); - if (conflict != null) { - conflicts.putValue(info.getElement(), XmlUtil.escape(conflict)); - } + protected static void checkConflicts(SimpleReference refUsages, MultiMap conflicts) { + for (UsageInfo info : refUsages.get()) { + String conflict = ((FixableUsageInfo)info).getConflictMessage(); + if (conflict != null) { + conflicts.putValue(info.getElement(), XmlUtil.escape(conflict)); + } + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java index ab445aab2..ca977c1e7 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java @@ -49,7 +49,7 @@ import consulo.util.collection.MultiMap; import consulo.util.lang.Comparing; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.io.IOException; @@ -59,7 +59,6 @@ import java.util.Set; public class WrapReturnValueProcessor extends FixableUsagesRefactoringProcessor { - private static final Logger LOG = Logger.getInstance("com.siyeh.rpp.wrapreturnvalue.WrapReturnValueProcessor"); private MoveDestination myMoveDestination; @@ -76,9 +75,11 @@ public class WrapReturnValueProcessor extends FixableUsagesRefactoringProcessor public WrapReturnValueProcessor( String className, String packageName, - MoveDestination moveDestination, PsiMethod method, + MoveDestination moveDestination, + PsiMethod method, boolean useExistingClass, - final boolean createInnerClass, PsiField delegateField + boolean createInnerClass, + PsiField delegateField ) { super(method.getProject()); myMoveDestination = moveDestination; @@ -90,9 +91,9 @@ public WrapReturnValueProcessor( myQualifiedName = StringUtil.getQualifiedName(packageName, className); this.myUseExistingClass = useExistingClass; - final Set typeParamSet = new HashSet<>(); - final TypeParametersVisitor visitor = new TypeParametersVisitor(typeParamSet); - final PsiTypeElement returnTypeElement = method.getReturnTypeElement(); + Set typeParamSet = new HashSet<>(); + TypeParametersVisitor visitor = new TypeParametersVisitor(typeParamSet); + PsiTypeElement returnTypeElement = method.getReturnTypeElement(); assert returnTypeElement != null; returnTypeElement.accept(visitor); typeParams = new ArrayList<>(typeParamSet); @@ -105,17 +106,17 @@ public WrapReturnValueProcessor( } private String calculateUnwrapMethodName() { - final PsiClass existingClass = + PsiClass existingClass = JavaPsiFacade.getInstance(myProject).findClass(myQualifiedName, GlobalSearchScope.allScope(myProject)); if (existingClass != null) { if (TypeConversionUtil.isPrimitiveWrapper(myQualifiedName)) { - final PsiPrimitiveType unboxedType = + PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(JavaPsiFacade.getInstance(myProject).getElementFactory().createType(existingClass)); assert unboxedType != null; return unboxedType.getCanonicalText() + "Value()"; } - final PsiMethod getter = PropertyUtil.findGetterForField(myDelegateField); + PsiMethod getter = PropertyUtil.findGetterForField(myDelegateField); return getter != null ? getter.getName() : ""; } return ""; @@ -139,20 +140,20 @@ public void findUsages(@Nonnull List usages) { @RequiredReadAction private void findUsagesForMethod(PsiMethod psiMethod, List usages) { for (PsiReference reference : ReferencesSearch.search(psiMethod, psiMethod.getUseScope())) { - final PsiElement referenceElement = reference.getElement(); - final PsiElement parent = referenceElement.getParent(); - if (parent instanceof PsiCallExpression) { - usages.add(new UnwrapCall((PsiCallExpression)parent, unwrapMethodName)); + PsiElement referenceElement = reference.getElement(); + PsiElement parent = referenceElement.getParent(); + if (parent instanceof PsiCallExpression callExpr) { + usages.add(new UnwrapCall(callExpr, unwrapMethodName)); } } - final String returnType = calculateReturnTypeString(); + String returnType = calculateReturnTypeString(); usages.add(new ChangeReturnType(psiMethod, returnType)); psiMethod.accept(new ReturnSearchVisitor(usages, returnType, psiMethod)); } private String calculateReturnTypeString() { - final String qualifiedName = StringUtil.getQualifiedName(packageName, className); - final StringBuilder returnTypeBuffer = new StringBuilder(qualifiedName); + String qualifiedName = StringUtil.getQualifiedName(packageName, className); + StringBuilder returnTypeBuffer = new StringBuilder(qualifiedName); if (!typeParams.isEmpty()) { returnTypeBuffer.append('<'); returnTypeBuffer.append(StringUtil.join( @@ -171,9 +172,9 @@ private String calculateReturnTypeString() { @Override @RequiredUIAccess - protected boolean preprocessUsages(@Nonnull final Ref refUsages) { + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { MultiMap conflicts = new MultiMap<>(); - final PsiClass existingClass = + PsiClass existingClass = JavaPsiFacade.getInstance(myProject).findClass(myQualifiedName, GlobalSearchScope.allScope(myProject)); if (myUseExistingClass) { if (existingClass == null) { @@ -181,9 +182,9 @@ protected boolean preprocessUsages(@Nonnull final Ref refUsages) { } else { boolean foundConstructor = false; - final Set returnTypes = new HashSet<>(); + Set returnTypes = new HashSet<>(); returnTypes.add(method.getReturnType()); - final PsiCodeBlock methodBody = method.getBody(); + PsiCodeBlock methodBody = method.getBody(); if (methodBody != null) { methodBody.accept(new JavaRecursiveElementWalkingVisitor() { @Override @@ -200,21 +201,21 @@ public void visitReturnStatement(@Nonnull PsiReturnStatement statement) { }); } - final PsiMethod[] constructors = existingClass.getConstructors(); + PsiMethod[] constructors = existingClass.getConstructors(); constr: for (PsiMethod constructor : constructors) { - final PsiParameter[] parameters = constructor.getParameterList().getParameters(); + PsiParameter[] parameters = constructor.getParameterList().getParameters(); if (parameters.length == 1) { - final PsiParameter parameter = parameters[0]; - final PsiType parameterType = parameter.getType(); + PsiParameter parameter = parameters[0]; + PsiType parameterType = parameter.getType(); for (PsiType returnType : returnTypes) { if (!TypeConversionUtil.isAssignable(parameterType, returnType)) { continue constr; } } - final PsiCodeBlock body = constructor.getBody(); + PsiCodeBlock body = constructor.getBody(); LOG.assertTrue(body != null); - final boolean[] found = new boolean[1]; + boolean[] found = new boolean[1]; body.accept(new JavaRecursiveElementWalkingVisitor() { @Override @RequiredReadAction @@ -264,7 +265,7 @@ public void visitAssignmentExpression(@Nonnull PsiAssignmentExpression expressio @Override @RequiredReadAction - protected void performRefactoring(UsageInfo[] usageInfos) { + protected void performRefactoring(@Nonnull UsageInfo[] usageInfos) { if (!myUseExistingClass && !buildClass()) { return; } @@ -273,18 +274,18 @@ protected void performRefactoring(UsageInfo[] usageInfos) { @RequiredReadAction private boolean buildClass() { - final PsiManager manager = method.getManager(); - final Project project = method.getProject(); - final ReturnValueBeanBuilder beanClassBuilder = new ReturnValueBeanBuilder(); + PsiManager manager = method.getManager(); + Project project = method.getProject(); + ReturnValueBeanBuilder beanClassBuilder = new ReturnValueBeanBuilder(); beanClassBuilder.setCodeStyleSettings(project); beanClassBuilder.setTypeArguments(typeParams); beanClassBuilder.setClassName(className); beanClassBuilder.setPackageName(packageName); - beanClassBuilder.setStatic(myCreateInnerClass && method.hasModifierProperty(PsiModifier.STATIC)); - final PsiType returnType = method.getReturnType(); + beanClassBuilder.setStatic(myCreateInnerClass && method.isStatic()); + PsiType returnType = method.getReturnType(); beanClassBuilder.setValueType(returnType); - final String classString; + String classString; try { classString = beanClassBuilder.buildBeanClass(); } @@ -294,30 +295,30 @@ private boolean buildClass() { } try { - final PsiFileFactory factory = PsiFileFactory.getInstance(project); - final PsiJavaFile psiFile = (PsiJavaFile)factory.createFileFromText(className + ".java", JavaFileType.INSTANCE, classString); - final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); + PsiFileFactory factory = PsiFileFactory.getInstance(project); + PsiJavaFile psiFile = (PsiJavaFile)factory.createFileFromText(className + ".java", JavaFileType.INSTANCE, classString); + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); if (myCreateInnerClass) { - final PsiClass containingClass = method.getContainingClass(); - final PsiElement innerClass = containingClass.add(psiFile.getClasses()[0]); + PsiClass containingClass = method.getContainingClass(); + PsiElement innerClass = containingClass.add(psiFile.getClasses()[0]); JavaCodeStyleManager.getInstance(project).shortenClassReferences(innerClass); } else { - final PsiFile containingFile = method.getContainingFile(); + PsiFile containingFile = method.getContainingFile(); - final PsiDirectory containingDirectory = containingFile.getContainingDirectory(); - final PsiDirectory directory; + PsiDirectory containingDirectory = containingFile.getContainingDirectory(); + PsiDirectory directory; if (myMoveDestination != null) { directory = myMoveDestination.getTargetDirectory(containingDirectory); } else { - final Module module = ModuleUtil.findModuleForPsiElement(containingFile); + Module module = ModuleUtil.findModuleForPsiElement(containingFile); directory = PackageUtil.findOrCreateDirectoryForPackage(module, packageName, containingDirectory, true, true); } if (directory != null) { - final PsiElement shortenedFile = JavaCodeStyleManager.getInstance(project).shortenClassReferences(psiFile); - final PsiElement reformattedFile = codeStyleManager.reformat(shortenedFile); + PsiElement shortenedFile = JavaCodeStyleManager.getInstance(project).shortenClassReferences(psiFile); + PsiElement reformattedFile = codeStyleManager.reformat(shortenedFile); directory.add(reformattedFile); } else { @@ -336,7 +337,7 @@ private boolean buildClass() { @Override @RequiredReadAction protected String getCommandName() { - final PsiClass containingClass = method.getContainingClass(); + PsiClass containingClass = method.getContainingClass(); return JavaRefactoringLocalize.wrappedReturnCommandName(className, containingClass.getName(), '.', method.getName()).get(); } @@ -345,7 +346,7 @@ private class ReturnSearchVisitor extends JavaRecursiveElementWalkingVisitor { private final String type; private final PsiMethod myMethod; - ReturnSearchVisitor(List usages, String type, final PsiMethod psiMethod) { + ReturnSearchVisitor(List usages, String type, PsiMethod psiMethod) { super(); this.usages = usages; this.type = type; @@ -364,15 +365,15 @@ public void visitReturnStatement(@Nonnull PsiReturnStatement statement) { return; } - final PsiExpression returnValue = statement.getReturnValue(); + PsiExpression returnValue = statement.getReturnValue(); if (myUseExistingClass && returnValue instanceof PsiMethodCallExpression call) { if (call.getArgumentList().getExpressions().length == 0) { - final PsiReferenceExpression callMethodExpression = call.getMethodExpression(); - final String methodName = callMethodExpression.getReferenceName(); + PsiReferenceExpression callMethodExpression = call.getMethodExpression(); + String methodName = callMethodExpression.getReferenceName(); if (Comparing.strEqual(unwrapMethodName, methodName)) { - final PsiExpression qualifier = callMethodExpression.getQualifierExpression(); + PsiExpression qualifier = callMethodExpression.getQualifierExpression(); if (qualifier != null) { - final PsiType qualifierType = qualifier.getType(); + PsiType qualifierType = qualifier.getType(); if (qualifierType != null && qualifierType.getCanonicalText().equals(myQualifiedName)) { usages.add(new ReturnWrappedValue(statement)); return; diff --git a/plugin/src/main/java/consulo/java/impl/refactoring/changeSignature/ChangeSignatureUsageProcessorEx.java b/plugin/src/main/java/consulo/java/impl/refactoring/changeSignature/ChangeSignatureUsageProcessorEx.java index 5fdfc0981..3ecf9a533 100644 --- a/plugin/src/main/java/consulo/java/impl/refactoring/changeSignature/ChangeSignatureUsageProcessorEx.java +++ b/plugin/src/main/java/consulo/java/impl/refactoring/changeSignature/ChangeSignatureUsageProcessorEx.java @@ -21,12 +21,12 @@ import consulo.language.editor.refactoring.changeSignature.ChangeInfo; import consulo.language.editor.refactoring.changeSignature.ChangeSignatureUsageProcessor; import consulo.usage.UsageInfo; +import consulo.util.lang.ref.SimpleReference; /** * @author VISTALL - * @since 26.06.14 + * @since 2014-06-26 */ -public interface ChangeSignatureUsageProcessorEx extends ChangeSignatureUsageProcessor -{ - boolean setupDefaultValues(ChangeInfo changeInfo, Ref refUsages, Project project); +public interface ChangeSignatureUsageProcessorEx extends ChangeSignatureUsageProcessor { + boolean setupDefaultValues(ChangeInfo changeInfo, SimpleReference refUsages, Project project); }