public static boolean isInside(PsiElement place, PsiElement ancestor) {
    if (SafeDeleteProcessor.isInside(place, ancestor)) return true;
    if (PsiTreeUtil.getParentOfType(place, PsiComment.class, false) != null
        && ancestor instanceof PsiClass) {
      final PsiClass aClass = (PsiClass) ancestor;
      if (aClass.getParent() instanceof PsiJavaFile) {
        final PsiJavaFile file = (PsiJavaFile) aClass.getParent();
        if (PsiTreeUtil.isAncestor(file, place, false)) {
          if (file.getClasses().length == 1) { // file will be deleted on class deletion
            return true;
          }
        }
      }
    }

    return false;
  }
  private static boolean containsOnlyPrivates(final PsiClass aClass) {
    final PsiField[] fields = aClass.getFields();
    for (PsiField field : fields) {
      if (!field.hasModifierProperty(PsiModifier.PRIVATE)) return false;
    }

    final PsiMethod[] methods = aClass.getMethods();
    for (PsiMethod method : methods) {
      if (!method.hasModifierProperty(PsiModifier.PRIVATE)) {
        if (method.isConstructor()) { // skip non-private constructors with call to super only
          final PsiCodeBlock body = method.getBody();
          if (body != null) {
            final PsiStatement[] statements = body.getStatements();
            if (statements.length == 0) continue;
            if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement) {
              final PsiExpression expression =
                  ((PsiExpressionStatement) statements[0]).getExpression();
              if (expression instanceof PsiMethodCallExpression) {
                PsiReferenceExpression methodExpression =
                    ((PsiMethodCallExpression) expression).getMethodExpression();
                if (methodExpression.getText().equals(PsiKeyword.SUPER)) {
                  continue;
                }
              }
            }
          }
        }
        return false;
      }
    }

    final PsiClass[] inners = aClass.getInnerClasses();
    for (PsiClass inner : inners) {
      if (!inner.hasModifierProperty(PsiModifier.PRIVATE)) return false;
    }

    return true;
  }
  public Collection<String> findConflicts(
      @NotNull final PsiElement element, @NotNull final PsiElement[] allElementsToDelete) {
    if (element instanceof PsiMethod) {
      final PsiClass containingClass = ((PsiMethod) element).getContainingClass();

      if (containingClass != null && !containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
        final PsiMethod[] superMethods = ((PsiMethod) element).findSuperMethods();
        for (PsiMethod superMethod : superMethods) {
          if (isInside(superMethod, allElementsToDelete)) continue;
          if (superMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
            String message =
                RefactoringBundle.message(
                    "0.implements.1",
                    RefactoringUIUtil.getDescription(element, true),
                    RefactoringUIUtil.getDescription(superMethod, true));
            return Collections.singletonList(message);
          }
        }
      }
    } else if (element instanceof PsiParameter) {
      final PsiElement scope = ((PsiParameter) element).getDeclarationScope();
      if (scope instanceof PsiMethod) {
        final PsiMethod method = (PsiMethod) scope;
        final PsiClass containingClass = method.getContainingClass();
        if (containingClass != null) {
          final int parameterIndex =
              method.getParameterList().getParameterIndex((PsiParameter) element);
          final PsiMethod methodCopy = (PsiMethod) method.copy();
          methodCopy.getParameterList().getParameters()[parameterIndex].delete();
          final MultiMap<PsiElement, String> conflicts = new MultiMap<>();
          ConflictsUtil.checkMethodConflicts(containingClass, method, methodCopy, conflicts);
          return (Collection<String>) conflicts.values();
        }
      }
    }
    return null;
  }
  private static void findClassUsages(
      final PsiClass psiClass,
      final PsiElement[] allElementsToDelete,
      final List<UsageInfo> usages) {
    final boolean justPrivates = containsOnlyPrivates(psiClass);
    final String qualifiedName = psiClass.getQualifiedName();
    final boolean annotationType = psiClass.isAnnotationType() && qualifiedName != null;

    ReferencesSearch.search(psiClass)
        .forEach(
            reference -> {
              final PsiElement element = reference.getElement();

              if (!isInside(element, allElementsToDelete)) {
                PsiElement parent = element.getParent();
                if (parent instanceof PsiReferenceList) {
                  final PsiElement pparent = parent.getParent();
                  if (pparent instanceof PsiClass
                      && element instanceof PsiJavaCodeReferenceElement) {
                    final PsiClass inheritor = (PsiClass) pparent;
                    // If psiClass contains only private members, then it is safe to remove it and
                    // change inheritor's extends/implements accordingly
                    if (justPrivates) {
                      if (parent.equals(inheritor.getExtendsList())
                          || parent.equals(inheritor.getImplementsList())) {
                        usages.add(
                            new SafeDeleteExtendsClassUsageInfo(
                                (PsiJavaCodeReferenceElement) element, psiClass, inheritor));
                        return true;
                      }
                    }
                  }
                }
                LOG.assertTrue(element.getTextRange() != null);
                final PsiFile containingFile = psiClass.getContainingFile();
                boolean sameFileWithSingleClass = false;
                if (containingFile instanceof PsiClassOwner) {
                  final PsiClass[] classes = ((PsiClassOwner) containingFile).getClasses();
                  sameFileWithSingleClass =
                      classes.length == 1
                          && classes[0] == psiClass
                          && element.getContainingFile() == containingFile;
                }

                final boolean safeDelete = sameFileWithSingleClass || isInNonStaticImport(element);
                if (annotationType && parent instanceof PsiAnnotation) {
                  usages.add(
                      new SafeDeleteAnnotation((PsiAnnotation) parent, psiClass, safeDelete));
                } else {
                  usages.add(
                      new SafeDeleteReferenceJavaDeleteUsageInfo(element, psiClass, safeDelete));
                }
              }
              return true;
            });
  }