void (@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); }