@Override
  public void actionPerformed(@NotNull AnActionEvent e) {
    final Project project = e.getProject();
    assert project != null;

    final Data topLevelData = new Data();
    final Data subData = new Data();

    final VirtualFile dir = e.getData(CommonDataKeys.VIRTUAL_FILE);
    assert dir != null;

    final List<VirtualFile> javaFiles = collectJavaFiles(dir, project);

    Runnable runnable = () -> {
      final PsiManager psiManager = PsiManager.getInstance(project);
      ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
      indicator.setIndeterminate(false);
      for (int i = 0; i < javaFiles.size(); i++) {
        VirtualFile file = javaFiles.get(i);
        indicator.setText2(file.getPath());
        indicator.setFraction((double)i / javaFiles.size());
        PsiFile psiFile = psiManager.findFile(file);
        if (psiFile instanceof PsiJavaFile) {
          psiFile.accept(new PsiRecursiveElementWalkingVisitor() {
            @Override
            public void visitElement(@NotNull PsiElement element) {
              if (element instanceof PsiIdentifier) {
                int offset = element.getTextRange().getStartOffset();
                PsiExpression minExpression = PsiTreeUtil.getParentOfType(element, PsiExpression.class);
                if (minExpression != null && minExpression.getTextRange().getStartOffset() == offset) {
                  PsiExpression maxExpression = minExpression;
                  while (true) {
                    PsiExpression nextExpression = PsiTreeUtil.getParentOfType(maxExpression, PsiExpression.class, true);
                    if (nextExpression == null || nextExpression.getTextRange().getStartOffset() != offset) break;
                    maxExpression = nextExpression;
                  }
                  collectExpressionData(minExpression, maxExpression, topLevelData, subData);
                }
              }

              super.visitElement(element);
            }
          });
        }
      }
    };
    ProgressResult<?> result = new ProgressRunner<>(() -> ApplicationManagerEx.getApplication().runReadAction(runnable))
      .sync()
      .onThread(ProgressRunner.ThreadToUse.POOLED)
      .modal()
      .submitAndGet();

    if (result.isCanceled()) {
      return;
    }

    Messages.showMessageDialog("Top-level: " + topLevelData + "\n\n" + "Sub-expressions: " + subData.toString(), "Expression Statistics", null);
  }
@Override
  public void actionPerformed(@NotNull AnActionEvent e)