void (final String visitorName, final PsiClass baseClass, final PsiDirectory directory, final GlobalSearchScope scope) { final Map<PsiClass, Set<PsiClass>> classes = new HashMap<>(); for (PsiClass aClass : ClassInheritorsSearch.search(baseClass, scope, true).findAll()) { if (aClass.hasModifierProperty(PsiModifier.ABSTRACT) == baseClass.hasModifierProperty(PsiModifier.ABSTRACT)) { final List<PsiClass> implementors = ContainerUtil.findAll(ClassInheritorsSearch.search(aClass).findAll(), psiClass -> !psiClass.hasModifierProperty(PsiModifier.ABSTRACT)); classes.put(aClass, new HashSet<>(implementors)); } } final Map<PsiClass, Set<PsiClass>> pathMap = new HashMap<>(); for (PsiClass aClass : classes.keySet()) { final Set<PsiClass> superClasses = new LinkedHashSet<>(); for (PsiClass superClass : aClass.getSupers()) { if (superClass.isInheritor(baseClass, true)) { superClasses.add(superClass); final Set<PsiClass> superImplementors = classes.get(superClass); if (superImplementors != null) { superImplementors.removeAll(classes.get(aClass)); } } } if (superClasses.isEmpty()) { superClasses.add(baseClass); } pathMap.put(aClass, superClasses); } pathMap.put(baseClass, Collections.emptySet()); final ArrayList<PsiFile> psiFiles = new ArrayList<>(); for (Set<PsiClass> implementors : classes.values()) { for (PsiClass psiClass : implementors) { psiFiles.add(psiClass.getContainingFile()); } } final Project project = baseClass.getProject(); final PsiClass visitorClass = JavaPsiFacade.getInstance(project).findClass(visitorName, GlobalSearchScope.projectScope(project)); if (visitorClass != null) { psiFiles.add(visitorClass.getContainingFile()); } final int finalDetectedPrefix = detectClassPrefix(classes.keySet()).length(); try { WriteCommandAction.writeCommandAction(project, PsiUtilCore.toPsiFileArray(psiFiles)) .withGlobalUndo() .run(() -> { if (visitorClass == null) { final String shortClassName = PsiNameHelper.getShortClassName(visitorName); if (directory != null) { final PsiClass vc = JavaDirectoryService.getInstance().createClass(directory, shortClassName); generateVisitorClass(vc, classes, pathMap, finalDetectedPrefix); } } else { generateVisitorClass(visitorClass, classes, pathMap, finalDetectedPrefix); } }); } catch (Throwable throwable) { throw new RuntimeException(throwable); } }