public static boolean processElementUsages(@NotNull PsiElement element,
                                             @NotNull FindUsagesOptions options,
                                             @NotNull Processor<? super UsageInfo> processor) {
    if (options instanceof JavaVariableFindUsagesOptions varOptions) {
      if (varOptions.isReadAccess || varOptions.isWriteAccess){
        if (varOptions.isReadAccess && varOptions.isWriteAccess){
          if (!addElementUsages(element, options, processor)) return false;
        }
        else{
          if (!addElementUsages(element, varOptions, info -> {
            PsiElement element1 = info.getElement();
            boolean isWrite = element1 instanceof PsiExpression expression1 && PsiUtil.isAccessedForWriting(expression1);
            if (isWrite == varOptions.isWriteAccess) {
              return processor.process(info);
            }
            return true;
          })) return false;
        }
      }
    }
    else if (options.isUsages) {
      if (!addElementUsages(element, options, processor)) return false;
    }

    boolean success = ReadAction.compute(() -> {
      if (ThrowSearchUtil.isSearchable(element) && options instanceof JavaThrowFindUsagesOptions javaOptions && options.isUsages) {
        ThrowSearchUtil.Root root = javaOptions.getRoot();
        if (root == null) {
          ThrowSearchUtil.Root[] roots = ThrowSearchUtil.getSearchRoots(element);
          if (roots != null && roots.length > 0) {
            root = roots [0];
          }
        }
        if (root != null) {
          return ThrowSearchUtil.addThrowUsages(processor, root, options);
        }
      }
      return true;
    });
    if (!success) return false;

    if (options instanceof JavaPackageFindUsagesOptions javaOptions && javaOptions.isClassesUsages){
      if (!addClassesUsages((PsiPackage)element, javaOptions, processor)) return false;
    }

    if (options instanceof JavaClassFindUsagesOptions classOptions && element instanceof PsiClass psiClass) {
      PsiManager manager = ReadAction.compute(() -> psiClass.getManager());
      if (classOptions.isMethodsUsages){
        if (!addMethodUsages(psiClass, manager, classOptions, processor)) return false;
      }
      if (classOptions.isFieldsUsages){
        if (!addFieldsUsages(psiClass, manager, classOptions, processor)) return false;
      }
      if (ReadAction.compute(() -> psiClass.isInterface())) {
        if (classOptions.isDerivedInterfaces){
          if (classOptions.isImplementingClasses){
            if (!addInheritors(psiClass, classOptions, processor)) return false;
          }
          else{
            if (!addDerivedInterfaces(psiClass, classOptions, processor)) return false;
          }
        }
        else if (classOptions.isImplementingClasses){
          if (!addImplementingClasses(psiClass, classOptions, processor)) return false;
        }

        if (classOptions.isImplementingClasses) {
          FunctionalExpressionSearch
            .search(psiClass, classOptions.searchScope).forEach(new PsiElementProcessorAdapter<>(
            expression -> addResult(expression, options, processor)));
        }
      }
      else if (classOptions.isDerivedClasses) {
        if (!addInheritors(psiClass, classOptions, processor)) return false;
      }
    }

    if (options instanceof JavaMethodFindUsagesOptions methodOptions) {
      PsiMethod psiMethod = (PsiMethod)element;
      boolean isAbstract = ReadAction.compute(() -> psiMethod.hasModifierProperty(PsiModifier.ABSTRACT));
      if (isAbstract ? methodOptions.isImplementingMethods : methodOptions.isOverridingMethods) {
        if (!processOverridingMethods(psiMethod, processor, methodOptions)) return false;
        FunctionalExpressionSearch.search(psiMethod, methodOptions.searchScope).forEach(new PsiElementProcessorAdapter<>(
          expression -> addResult(expression, options, processor)));
      }
      if (ReadAction.compute(() -> ImplicitToStringSearch.isToStringMethod(psiMethod)) && methodOptions.isImplicitToString) {
        ImplicitToStringSearch.search(psiMethod, methodOptions.searchScope).forEach(new PsiElementProcessorAdapter<>(ref -> addResult(ref, options, processor)));
      }
    }

    if (element instanceof PomTarget pomTarget) {
       if (!addAliasingUsages(pomTarget, options, processor)) return false;
    }
    Boolean isSearchable = ReadAction.compute(() -> ThrowSearchUtil.isSearchable(element));
    if (!isSearchable && options.isSearchForTextOccurrences && options.searchScope instanceof GlobalSearchScope globalSearchScope) {
      Collection<String> stringsToSearch = ReadAction.compute(() -> getElementNames(element));
      // todo add to fastTrack
      return FindUsagesHelper.processUsagesInText(element, stringsToSearch, false, globalSearchScope, processor);
    }
    return true;
  }
public static boolean processElementUsages(@NotNull PsiElement element,
                                             @NotNull FindUsagesOptions options,
                                             @NotNull Processor<? super UsageInfo> processor)