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(); }
public static SafeDeleteProcessor createInstance( Project project, @Nullable Runnable prepareSuccessfulCallBack, PsiElement[] elementsToDelete, boolean isSearchInComments, boolean isSearchNonJava, boolean askForAccessors) { ArrayList<PsiElement> elements = new ArrayList<PsiElement>(Arrays.asList(elementsToDelete)); HashSet<PsiElement> elementsToDeleteSet = new HashSet<PsiElement>(Arrays.asList(elementsToDelete)); for (PsiElement psiElement : elementsToDelete) { for (SafeDeleteProcessorDelegate delegate : Extensions.getExtensions(SafeDeleteProcessorDelegate.EP_NAME)) { if (delegate.handlesElement(psiElement)) { Collection<PsiElement> addedElements = delegate.getAdditionalElementsToDelete( psiElement, elementsToDeleteSet, askForAccessors); if (addedElements != null) { elements.addAll(addedElements); } break; } } } return new SafeDeleteProcessor( project, prepareSuccessfulCallBack, PsiUtilCore.toPsiElementArray(elements), isSearchInComments, isSearchNonJava); }
private static UsageInfo[] filterToBeDeleted(UsageInfo[] infos) { ArrayList<UsageInfo> list = new ArrayList<UsageInfo>(); for (UsageInfo info : infos) { if (!(info instanceof SafeDeleteReferenceUsageInfo) || ((SafeDeleteReferenceUsageInfo) info).isSafeDelete()) { list.add(info); } } return list.toArray(new UsageInfo[list.size()]); }
@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); } }
private static PsiMethod[] removeDeletedMethods( PsiMethod[] methods, final PsiElement[] allElementsToDelete) { ArrayList<PsiMethod> list = new ArrayList<>(); for (PsiMethod method : methods) { boolean isDeleted = false; for (PsiElement element : allElementsToDelete) { if (element == method) { isDeleted = true; break; } } if (!isDeleted) { list.add(method); } } return list.toArray(new PsiMethod[list.size()]); }
@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()]); }
@Nullable @Override public Collection<? extends PsiElement> getElementsToSearch( @NotNull PsiElement element, @Nullable Module module, @NotNull Collection<PsiElement> allElementsToDelete) { Project project = element.getProject(); if (element instanceof PsiPackage && module != null) { final PsiDirectory[] directories = ((PsiPackage) element).getDirectories(module.getModuleScope()); if (directories.length == 0) return null; return Arrays.asList(directories); } else if (element instanceof PsiMethod) { final PsiMethod[] methods = SuperMethodWarningUtil.checkSuperMethods( (PsiMethod) element, RefactoringBundle.message("to.delete.with.usage.search"), allElementsToDelete); if (methods.length == 0) return null; final ArrayList<PsiMethod> psiMethods = new ArrayList<>(Arrays.asList(methods)); psiMethods.add((PsiMethod) element); return psiMethods; } else if (element instanceof PsiParameter && ((PsiParameter) element).getDeclarationScope() instanceof PsiMethod) { PsiMethod method = (PsiMethod) ((PsiParameter) element).getDeclarationScope(); final Set<PsiParameter> parametersToDelete = new HashSet<>(); parametersToDelete.add((PsiParameter) element); final int parameterIndex = method.getParameterList().getParameterIndex((PsiParameter) element); final List<PsiMethod> superMethods = new ArrayList<>(Arrays.asList(method.findDeepestSuperMethods())); if (superMethods.isEmpty()) { superMethods.add(method); } for (PsiMethod superMethod : superMethods) { parametersToDelete.add(superMethod.getParameterList().getParameters()[parameterIndex]); OverridingMethodsSearch.search(superMethod) .forEach( overrider -> { parametersToDelete.add( overrider.getParameterList().getParameters()[parameterIndex]); return true; }); } if (parametersToDelete.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode()) { String message = RefactoringBundle.message( "0.is.a.part.of.method.hierarchy.do.you.want.to.delete.multiple.parameters", UsageViewUtil.getLongName(method)); int result = Messages.showYesNoCancelDialog( project, message, SafeDeleteHandler.REFACTORING_NAME, Messages.getQuestionIcon()); if (result == Messages.CANCEL) return null; if (result == Messages.NO) return Collections.singletonList(element); } return parametersToDelete; } else if (element instanceof PsiTypeParameter) { final PsiTypeParameterListOwner owner = ((PsiTypeParameter) element).getOwner(); if (owner instanceof PsiMethod && !owner.hasModifierProperty(PsiModifier.STATIC)) { final PsiTypeParameterList typeParameterList = owner.getTypeParameterList(); if (typeParameterList != null) { final int index = typeParameterList.getTypeParameterIndex((PsiTypeParameter) element); if (index >= 0) { final ArrayList<PsiTypeParameter> overriders = new ArrayList<>(); overriders.add((PsiTypeParameter) element); OverridingMethodsSearch.search((PsiMethod) owner) .forEach( overrider -> { final PsiTypeParameter[] typeParameters = overrider.getTypeParameters(); if (index < typeParameters.length) { overriders.add(typeParameters[index]); } return true; }); if (overriders.size() > 1) { String message = RefactoringBundle.message( "0.is.a.part.of.method.hierarchy.do.you.want.to.delete.multiple.type.parameters", UsageViewUtil.getLongName(owner)); int result = ApplicationManager.getApplication().isUnitTestMode() ? Messages.YES : Messages.showYesNoCancelDialog( project, message, SafeDeleteHandler.REFACTORING_NAME, Messages.getQuestionIcon()); if (result == Messages.CANCEL) return null; if (result == Messages.YES) return overriders; } } } } } return Collections.singletonList(element); }