public static Future<Collection<Usage>> showElementUsagesWithResult(@NotNull ShowUsagesParameters parameters,
                                                                      @NotNull ShowUsagesActionHandler actionHandler,
                                                                      @NotNull UsageViewImpl usageView) {

    Span findUsageSpan = myFindUsagesTracer.spanBuilder("findUsages").startSpan();
    Scope opentelemetryScope = findUsageSpan.makeCurrent();
    Span popupSpan = myFindUsagesTracer.spanBuilder("findUsage_popup").startSpan();
    Span firstUsageSpan = myFindUsagesTracer.spanBuilder("findUsages_firstUsage").startSpan();

    Project project = parameters.project;
    ReadAction.nonBlocking(() -> actionHandler.getEventData()).submit(AppExecutorUtil.getAppExecutorService()).onSuccess(
      (eventData) -> UsageViewStatisticsCollector.logSearchStarted(project, usageView, CodeNavigateSource.ShowUsagesPopup, eventData));
    final SearchScope searchScope = actionHandler.getSelectedScope();
    final AtomicInteger outOfScopeUsages = new AtomicInteger();
    AtomicBoolean manuallyResized = new AtomicBoolean();
    Ref<UsageNode> preselectedRow = new Ref<>();

    Predicate<? super Usage> originUsageCheck = originUsageCheck(parameters.editor);
    ShowUsagesTableCellRenderer renderer = new ShowUsagesTableCellRenderer(originUsageCheck, outOfScopeUsages, searchScope);
    ShowUsagesTable table = new ShowUsagesTable(renderer, usageView);

    addUsageNodes(usageView.getRoot(), new ArrayList<>());

    List<Usage> usages = new ArrayList<>();
    Set<Usage> visibleUsages = new LinkedHashSet<>();
    table.setTableModel(new SmartList<>(new StringNode(UsageViewBundle.message("progress.searching"))));

    ShowUsagesPopupData showUsagesPopupData = new ShowUsagesPopupData(parameters, table, actionHandler, usageView);

    Runnable itemChosenCallback = table.prepareTable(
      showMoreUsagesRunnable(parameters, actionHandler),
      showUsagesInMaximalScopeRunnable(parameters, actionHandler, showUsagesPopupData),
      actionHandler
    );

    Consumer<AbstractPopup> tableResizer = popup -> {
      if (popup != null && popup.isVisible() && !manuallyResized.get()) {
        PropertiesComponent properties = PropertiesComponent.getInstance(project);
        int dataSize = table.getModel().getRowCount();
        setPopupSize(table, popup, parameters.popupPosition, parameters.minWidth, properties.isValueSet(PREVIEW_PROPERTY_KEY), dataSize);
      }
    };

    AbstractPopup popup = createUsagePopup(usageView, showUsagesPopupData, itemChosenCallback, tableResizer);
    popup.addResizeListener(() -> manuallyResized.set(true), popup);
    Ref<Long> popupShownTimeRef = new Ref<>();
    popup.addListener(new JBPopupListener() {
      @Override
      public void onClosed(@NotNull LightweightWindowEvent event) {
        @Nullable UsageNode node = getSelectedUsageNode(table);
        Usage usage = node != null ? node.getUsage() : null;
        UsageInfo2UsageAdapter usageAdapter = ObjectUtils.tryCast(usage, UsageInfo2UsageAdapter.class);
        UsageInfo usageInfo = usageAdapter != null ? usageAdapter.getUsageInfo() : null;
        int preselectedRowNumber = getRowNumber(preselectedRow.get(), table);
        int selectedRowNumber = getRowNumber(node, table);
        Long popupShownTime = popupShownTimeRef.get();
        Long durationTime = popupShownTime != null ? System.currentTimeMillis() - popupShownTime : null;
        ReadAction.nonBlocking(() ->
                                 actionHandler.buildFinishEventData(usageInfo)
        ).submit(AppExecutorUtil.getAppExecutorService()).onSuccess((finishEventData) -> {
          UsageViewStatisticsCollector.logPopupClosed(project, usageView, event.isOk(),
                                                      preselectedRowNumber,
                                                      selectedRowNumber, visibleUsages.size(),
                                                      durationTime,
                                                      finishEventData
          );
        });
      }
    });
    ProgressIndicator indicator = new ProgressIndicatorBase();
    if (!popup.isDisposed()) {
      Disposer.register(popup, usageView);
      Disposer.register(popup, indicator::cancel);

      // show popup only if find usages takes more than 300ms, otherwise it would flicker needlessly
      EdtScheduledExecutorService.getInstance().schedule(() -> {
        if (!usageView.isDisposed()) {
          showPopupIfNeedTo(popup, parameters.popupPosition, popupShownTimeRef);
          popupSpan.end();
        }
      }, ourPopupDelayTimeout, TimeUnit.MILLISECONDS);
    }

    UsageNode USAGES_OUTSIDE_SCOPE_NODE = new UsageNode(null, table.USAGES_OUTSIDE_SCOPE_SEPARATOR);
    UsageNode MORE_USAGES_SEPARATOR_NODE = new UsageNode(null, table.MORE_USAGES_SEPARATOR);

    Runnable runnable = () -> {
      if (popup.isDisposed()) return;

      List<UsageNode> nodes = new ArrayList<>(usages.size());
      List<Usage> copy;
      synchronized (usages) {
        // open up popup as soon as the first usage has been found
        if (!popup.isVisible() && (usages.isEmpty() || !showPopupIfNeedTo(popup, parameters.popupPosition, popupShownTimeRef))) {
          return;
        }
        addUsageNodes(usageView.getRoot(), nodes);
        copy = new ArrayList<>(usages);
      }

      boolean shouldShowMoreSeparator = copy.contains(table.MORE_USAGES_SEPARATOR);
      if (shouldShowMoreSeparator) {
        nodes.add(MORE_USAGES_SEPARATOR_NODE);
      }
      boolean hasOutsideScopeUsages = copy.contains(table.USAGES_OUTSIDE_SCOPE_SEPARATOR);
      if (hasOutsideScopeUsages && !shouldShowMoreSeparator) {
        nodes.add(USAGES_OUTSIDE_SCOPE_NODE);
      }
      List<UsageNode> data = new ArrayList<>(nodes);
      int filteredOutCount = usageView.getFilteredOutNodeCount();
      if (filteredOutCount != 0) {
        DefaultActionGroup filteringActions = popup.getUserData(DefaultActionGroup.class);
        if (filteringActions == null) return;

        List<ToggleAction> unselectedActions = Arrays.stream(filteringActions.getChildren(ActionManager.getInstance()))
          .filter(action -> action instanceof ToggleAction)
          .map(action -> (ToggleAction)action)
          .filter(ta -> !ta.isSelected(fakeEvent(ta)))
          .filter(ta -> !StringUtil.isEmpty(ta.getTemplatePresentation().getText()))
          .collect(Collectors.toList());
        data.add(new FilteredOutUsagesNode(table.USAGES_FILTERED_OUT_SEPARATOR,
                                           UsageViewBundle.message("usages.were.filtered.out", filteredOutCount),
                                           UsageViewBundle.message("usages.were.filtered.out.tooltip")) {
          @Override
          public void onSelected() {
            actionHandler.beforeClose(CLOSE_REASON_RESET_FILTERS);

            // toggle back unselected toggle actions
            toggleFilters(unselectedActions);
            // and restart show usages in hope it will show filtered out items now
            showElementUsages(parameters, actionHandler);
          }
        });
      }
      data.sort(new UsageNodeComparator(table));

      boolean hasMore = shouldShowMoreSeparator || hasOutsideScopeUsages;
      int totalCount = copy.size();
      int visibleCount = totalCount - filteredOutCount;
      showUsagesPopupData.header.setStatusText(hasMore, visibleCount, totalCount);
      rebuildTable(project, originUsageCheck, data, table, popup, parameters.popupPosition, parameters.minWidth, manuallyResized);
      preselectedRow.set(getSelectedUsageNode(table));
    };
    PingEDT pingEDT = new PingEDT("Rebuild popup in EDT", () -> popup.isDisposed(), 100, runnable);

    MessageBusConnection messageBusConnection = project.getMessageBus().connect(usageView);
    messageBusConnection.subscribe(UsageFilteringRuleProvider.RULES_CHANGED, () -> rulesChanged(usageView, pingEDT, popup));

    AtomicLong firstUsageAddedTS = new AtomicLong();
    AtomicBoolean tooManyResults = new AtomicBoolean();
    GlobalSearchScope everythingScope = GlobalSearchScope.everythingScope(project);
    Processor<Usage> collect = usage -> {
      if (!UsageViewManagerImpl.isInScope(usage, searchScope, everythingScope)) {
        if (outOfScopeUsages.getAndIncrement() == 0) {
          visibleUsages.add(USAGES_OUTSIDE_SCOPE_NODE.getUsage());
          usages.add(table.USAGES_OUTSIDE_SCOPE_SEPARATOR);
        }
        return true;
      }
      synchronized (usages) {
        firstUsageSpan.end();
        if (visibleUsages.size() >= parameters.maxUsages) {
          tooManyResults.set(true);
          return false;
        }

        UsageNode nodes = ReadAction.compute(() -> usageView.doAppendUsage(usage));
        usages.add(usage);
        firstUsageAddedTS.compareAndSet(0, System.nanoTime()); // Successes only once - at first assignment

        if (nodes != null) {
          visibleUsages.add(nodes.getUsage());
          boolean continueSearch = true;
          if (visibleUsages.size() == parameters.maxUsages) {
            visibleUsages.add(MORE_USAGES_SEPARATOR_NODE.getUsage());
            usages.add(table.MORE_USAGES_SEPARATOR);
            continueSearch = false;
          }
          pingEDT.ping();

          return continueSearch;
        }
      }

      return true;
    };

    UsageSearcher usageSearcher = actionHandler.createUsageSearcher();
    long searchStarted = System.nanoTime();
    CompletableFuture<Collection<Usage>> result = new CompletableFuture<>();
    FindUsagesManager.startProcessUsages(indicator, project, usageSearcher, collect, () -> ApplicationManager.getApplication().invokeLater(
      () -> {
        showUsagesPopupData.header.disposeProcessIcon();
        pingEDT.ping(); // repaint status
        synchronized (usages) {
          findUsageSpan.setAttribute("number", usages.size());
          if (visibleUsages.isEmpty()) {
            if (usages.isEmpty()) {
              String hint = UsageViewBundle.message("no.usages.found.in", searchScope.getDisplayName());
              hint(false, hint, parameters, actionHandler);
              cancel(popup);
            }
            // else all usages filtered out
          }
          else if (visibleUsages.size() == 1 && actionHandler.navigateToSingleUsageImmediately()) {
            if (usages.size() == 1) {
              //the only usage
              Usage usage = visibleUsages.iterator().next();
              if (usage == table.USAGES_OUTSIDE_SCOPE_SEPARATOR) {
                String hint = UsageViewManagerImpl.outOfScopeMessage(outOfScopeUsages.get(), searchScope);
                hint(true, hint, parameters, actionHandler);
                cancel(popup);
              }
              else {
                String hint = UsageViewBundle.message("show.usages.only.usage", searchScope.getDisplayName());
                navigateAndHint(project, usage, hint, parameters, actionHandler, () -> cancel(popup));
              }
            }
            else {
              assert usages.size() > 1 : usages;
              // usage view can filter usages down to one
              Usage visibleUsage = visibleUsages.iterator().next();
              if (areAllUsagesInOneLine(visibleUsage, usages)) {
                String hint = UsageViewBundle.message("all.usages.are.in.this.line", usages.size(), searchScope.getDisplayName());
                navigateAndHint(project, visibleUsage, hint, parameters, actionHandler, () -> cancel(popup));
              }
            }
          }
          result.complete(usages);
        }
        findUsageSpan.end();
        long current = System.nanoTime();
        UsageViewStatisticsCollector.logSearchFinished(project, usageView,
                                                       actionHandler.getTargetClass(), searchScope, actionHandler.getTargetLanguage(),
                                                       visibleUsages.size(),
                                                       TimeUnit.NANOSECONDS.toMillis(firstUsageAddedTS.get() - searchStarted),
                                                       TimeUnit.NANOSECONDS.toMillis(current - searchStarted),
                                                       tooManyResults.get(),
                                                       indicator.isCanceled(),
                                                       CodeNavigateSource.ShowUsagesPopup);
      },
      project.getDisposed()
    ));
    opentelemetryScope.close();
    actionHandler.afterOpen(popup);
    return result;
  }
public static Future<Collection<Usage>> showElementUsagesWithResult(@NotNull ShowUsagesParameters parameters,
                                                                      @NotNull ShowUsagesActionHandler actionHandler,
                                                                      @NotNull UsageViewImpl usageView)