private static Set<PsiMethod> validateOverridingMethods(
      PsiMethod originalMethod,
      final Collection<PsiReference> originalReferences,
      Collection<PsiMethod> overridingMethods,
      HashMap<PsiMethod, Collection<PsiReference>> methodToReferences,
      List<UsageInfo> usages,
      final PsiElement[] allElementsToDelete) {
    Set<PsiMethod> validOverriding = new LinkedHashSet<>(overridingMethods);
    Set<PsiMethod> multipleInterfaceImplementations = new HashSet<>();
    boolean anyNewBadRefs;
    do {
      anyNewBadRefs = false;
      for (PsiMethod overridingMethod : overridingMethods) {
        if (validOverriding.contains(overridingMethod)) {
          final Collection<PsiReference> overridingReferences =
              methodToReferences.get(overridingMethod);
          boolean anyOverridingRefs = false;
          for (final PsiReference overridingReference : overridingReferences) {
            final PsiElement element = overridingReference.getElement();
            if (!isInside(element, allElementsToDelete) && !isInside(element, validOverriding)) {
              anyOverridingRefs = true;
              break;
            }
          }
          if (!anyOverridingRefs
              && isMultipleInterfacesImplementation(
                  overridingMethod, originalMethod, allElementsToDelete)) {
            anyOverridingRefs = true;
            multipleInterfaceImplementations.add(overridingMethod);
          }

          if (anyOverridingRefs) {
            validOverriding.remove(overridingMethod);
            anyNewBadRefs = true;

            for (PsiReference reference : originalReferences) {
              final PsiElement element = reference.getElement();
              if (!isInside(element, allElementsToDelete)
                  && !isInside(element, overridingMethods)) {
                usages.add(
                    new SafeDeleteReferenceJavaDeleteUsageInfo(element, originalMethod, false));
                validOverriding.clear();
              }
            }
          }
        }
      }
    } while (anyNewBadRefs && !validOverriding.isEmpty());

    for (PsiMethod method : validOverriding) {
      if (method != originalMethod) {

        usages.add(new SafeDeleteOverridingMethodUsageInfo(method, originalMethod));
      }
    }

    for (PsiMethod method : overridingMethods) {
      if (!validOverriding.contains(method)
          && !multipleInterfaceImplementations.contains(method)
          && canBePrivate(
              method, methodToReferences.get(method), validOverriding, allElementsToDelete)) {
        usages.add(new SafeDeletePrivatizeMethod(method, originalMethod));
      } else {
        usages.add(new SafeDeleteOverrideAnnotation(method, originalMethod));
      }
    }
    return validOverriding;
  }
  @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);
  }