private static boolean allSuperMethodsSelectedToDelete( List<PsiMethod> unselectedMethods, PsiMethod method) { final ArrayList<PsiMethod> superMethods = new ArrayList<>(Arrays.asList(method.findSuperMethods())); superMethods.retainAll(unselectedMethods); return superMethods.isEmpty(); }
@Override public void run() { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); myUsageView.close(); ArrayList<PsiElement> elements = new ArrayList<PsiElement>(); for (SmartPsiElementPointer pointer : myPointers) { final PsiElement element = pointer.getElement(); if (element != null) { elements.add(element); } } if (!elements.isEmpty()) { SafeDeleteHandler.invoke(myProject, PsiUtilCore.toPsiElementArray(elements), true); } }
@Override protected boolean preprocessUsages(@NotNull Ref<UsageInfo[]> refUsages) { UsageInfo[] usages = refUsages.get(); ArrayList<String> conflicts = new ArrayList<String>(); for (PsiElement element : myElements) { for (SafeDeleteProcessorDelegate delegate : Extensions.getExtensions(SafeDeleteProcessorDelegate.EP_NAME)) { if (delegate.handlesElement(element)) { Collection<String> foundConflicts = delegate instanceof SafeDeleteProcessorDelegateBase ? ((SafeDeleteProcessorDelegateBase) delegate) .findConflicts(element, myElements, usages) : delegate.findConflicts(element, myElements); if (foundConflicts != null) { conflicts.addAll(foundConflicts); } break; } } } final HashMap<PsiElement, UsageHolder> elementsToUsageHolders = sortUsages(usages); final Collection<UsageHolder> usageHolders = elementsToUsageHolders.values(); for (UsageHolder usageHolder : usageHolders) { if (usageHolder.hasUnsafeUsagesInCode()) { conflicts.add(usageHolder.getDescription()); } } if (!conflicts.isEmpty()) { final RefactoringEventData conflictData = new RefactoringEventData(); conflictData.putUserData(RefactoringEventData.CONFLICTS_KEY, conflicts); myProject .getMessageBus() .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC) .conflictsDetected("refactoring.safeDelete", conflictData); if (ApplicationManager.getApplication().isUnitTestMode()) { if (!ConflictsInTestsException.isTestIgnore()) throw new ConflictsInTestsException(conflicts); } else { UnsafeUsagesDialog dialog = new UnsafeUsagesDialog(ArrayUtil.toStringArray(conflicts), myProject); if (!dialog.showAndGet()) { final int exitCode = dialog.getExitCode(); prepareSuccessful(); // dialog is always dismissed; if (exitCode == UnsafeUsagesDialog.VIEW_USAGES_EXIT_CODE) { showUsages( Arrays.stream(usages) .filter( usage -> usage instanceof SafeDeleteReferenceUsageInfo && !((SafeDeleteReferenceUsageInfo) usage).isSafeDelete()) .toArray(UsageInfo[]::new)); } return false; } else { myPreviewNonCodeUsages = false; } } } UsageInfo[] preprocessedUsages = usages; for (SafeDeleteProcessorDelegate delegate : Extensions.getExtensions(SafeDeleteProcessorDelegate.EP_NAME)) { preprocessedUsages = delegate.preprocessUsages(myProject, preprocessedUsages); if (preprocessedUsages == null) return false; } final UsageInfo[] filteredUsages = UsageViewUtil.removeDuplicatedUsages(preprocessedUsages); prepareSuccessful(); // dialog is always dismissed if (filteredUsages == null) { return false; } refUsages.set(filteredUsages); return true; }
@Nullable public UsageInfo[] preprocessUsages(final Project project, final UsageInfo[] usages) { final ArrayList<UsageInfo> result = new ArrayList<>(); final ArrayList<UsageInfo> overridingMethods = new ArrayList<>(); final ArrayList<SafeDeleteParameterCallHierarchyUsageInfo> delegatingParams = new ArrayList<>(); final ArrayList<SafeDeleteMethodCalleeUsageInfo> calleesSafeToDelete = new ArrayList<>(); for (UsageInfo usage : usages) { if (usage.isNonCodeUsage) { result.add(usage); } else if (usage instanceof SafeDeleteMethodCalleeUsageInfo) { calleesSafeToDelete.add((SafeDeleteMethodCalleeUsageInfo) usage); } else if (usage instanceof SafeDeleteOverridingMethodUsageInfo) { overridingMethods.add(usage); } else if (usage instanceof SafeDeleteParameterCallHierarchyUsageInfo) { delegatingParams.add((SafeDeleteParameterCallHierarchyUsageInfo) usage); } else if (usage instanceof SafeDeleteAnnotation) { result.add( new SafeDeleteAnnotation( (PsiAnnotation) usage.getElement(), ((SafeDeleteAnnotation) usage).getReferencedElement(), true)); } else { result.add(usage); } } if (!overridingMethods.isEmpty()) { if (ApplicationManager.getApplication().isUnitTestMode()) { result.addAll(overridingMethods); } else { OverridingMethodsDialog dialog = new OverridingMethodsDialog(project, overridingMethods); if (!dialog.showAndGet()) { return null; } final ArrayList<UsageInfo> selected = dialog.getSelected(); final Set<UsageInfo> unselected = new HashSet<>(overridingMethods); unselected.removeAll(selected); if (!unselected.isEmpty()) { final List<PsiMethod> unselectedMethods = ContainerUtil.map( unselected, info -> ((SafeDeleteOverridingMethodUsageInfo) info).getOverridingMethod()); for (Iterator<UsageInfo> iterator = result.iterator(); iterator.hasNext(); ) { final UsageInfo info = iterator.next(); if (info instanceof SafeDeleteOverrideAnnotation && !allSuperMethodsSelectedToDelete( unselectedMethods, ((SafeDeleteOverrideAnnotation) info).getMethod())) { iterator.remove(); } } } result.addAll(selected); } } if (!delegatingParams.isEmpty()) { final SafeDeleteParameterCallHierarchyUsageInfo parameterHierarchyUsageInfo = delegatingParams.get(0); if (ApplicationManager.getApplication().isUnitTestMode()) { result.addAll(delegatingParams); } else { final PsiMethod method = parameterHierarchyUsageInfo.getCalledMethod(); final PsiParameter parameter = parameterHierarchyUsageInfo.getReferencedElement(); final int parameterIndex = method.getParameterList().getParameterIndex(parameter); final JavaCallerChooser chooser = new SafeDeleteJavaCallerChooser(method, project, result) { @Override protected ArrayList<SafeDeleteParameterCallHierarchyUsageInfo> getTopLevelItems() { return delegatingParams; } @Override protected int getParameterIdx() { return parameterIndex; } }; TreeUtil.expand(chooser.getTree(), 2); if (!chooser.showAndGet()) { return null; } } } if (!calleesSafeToDelete.isEmpty()) { if (ApplicationManager.getApplication().isUnitTestMode()) { result.addAll(calleesSafeToDelete); } else { final PsiMethod method = calleesSafeToDelete.get(0).getCallerMethod(); final ArrayList<UsageInfo> list = new ArrayList<>(); JavaCallerChooser chooser = new SafeDeleteJavaCalleeChooser(method, project, list) { @Override protected ArrayList<SafeDeleteMethodCalleeUsageInfo> getTopLevelItems() { return calleesSafeToDelete; } }; TreeUtil.expand(chooser.getTree(), 2); if (!chooser.showAndGet()) { return null; } result.addAll(list); final List<PsiElement> methodsToDelete = new ArrayList<>(); for (UsageInfo info : list) { methodsToDelete.add(info.getElement()); } methodsToDelete.add(method); final Condition<PsiElement> insideDeletedCondition = getUsageInsideDeletedFilter( methodsToDelete.toArray(new PsiElement[methodsToDelete.size()])); for (UsageInfo info : list) { SafeDeleteProcessor.addNonCodeUsages( info.getElement(), result, insideDeletedCondition, JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD, JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD); } } } return result.toArray(new UsageInfo[result.size()]); }