@NotNull
  private Set<ModuleNode> prepareModulesWithDependencies(@NotNull Map<String, Set<ModuleNode>> packagesDeclaredInModules) {
    // get indexes
    final ProjectFileIndex projectFileIndex = ProjectFileIndex.getInstance(myProject);
    final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject);

    // prepare caches
    final Set<ModuleNode> modules = packagesDeclaredInModules.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
    final Map<PsiJavaModule, ModuleNode> nodeByDescriptor = new HashMap<>();
    final Map<Module, ModuleNode> nodeByModule = new HashMap<>();
    final Map<Library, ModuleNode> nodeByLibrary = new HashMap<>();
    for (ModuleNode module : modules) {
      if (module.getModule() != null) {
        nodeByModule.put(module.getModule(), module);
      }
    }

    // calculate dependencies
    for (ModuleNode module : modules) {
      if (module.getDescriptor() != null) {
        nodeByDescriptor.put(module.getDescriptor(), module);
      }
      if (module.getModule() != null) {
        // compare with JPS model
        final OrderEntry[] entries = ModuleRootManager.getInstance(module.getModule()).getOrderEntries();
        for (OrderEntry entry : entries) {
          if (!(entry instanceof ExportableOrderEntry)) continue;
          if (entry instanceof ModuleOrderEntry moduleOrderEntry && moduleOrderEntry.getModule() != null) {
            if (moduleOrderEntry.isExported()) { // use all transitive dependencies
              ModuleNode node = nodeByModule.get(moduleOrderEntry.getModule());
              if (node == null) continue;
              module.getDependencies().compute(node, (key, old) -> merge(old, Set.of(TRANSITIVE),
                                                                         () -> EnumSet.noneOf(DependencyType.class)));
            }
            else {
              for (String aPackage : module.getRequiredPackages()) {
                final Set<ModuleNode> nodes = packagesDeclaredInModules.getOrDefault(aPackage, Set.of());
                for (ModuleNode node : nodes) {
                  if (module.getDependencies().containsKey(node)) continue;
                  if (!moduleOrderEntry.getModule().equals(node.getModule())) continue;
                  module.getDependencies().computeIfAbsent(node, k -> Set.of());
                }
                final PsiPackage psiPackage = ReadAction.compute(() -> psiFacade.findPackage(aPackage));
                if (psiPackage == null) continue;
                for (PsiDirectory directory : ReadAction.compute(() -> psiPackage.getDirectories())) {
                  final VirtualFile file = directory.getVirtualFile();
                  final List<OrderEntry> indexedOrderEntries = ReadAction.compute(() -> projectFileIndex.getOrderEntriesForFile(file));
                  if (!indexedOrderEntries.contains(moduleOrderEntry)) continue;
                  final ModuleNode node = nodeByModule.get(moduleOrderEntry.getModule());
                  if (node == null) continue;
                  module.getDependencies().computeIfAbsent(node, k -> Set.of());
                }
              }
            }
          }
          else if (entry instanceof LibraryOrderEntry libraryOrderEntry && libraryOrderEntry.getLibrary() != null) {
            final Library library = libraryOrderEntry.getLibrary();
            if (library == null) continue;
            final ModuleNode cachedNode = nodeByLibrary.computeIfAbsent(library, lib -> findLibraryNode(packagesDeclaredInModules,
                                                                                                        nodeByDescriptor, myProject, lib));
            if (cachedNode == null) continue;
            nodeByLibrary.put(library, cachedNode);
            if (libraryOrderEntry.isExported()) { // use all transitive libraries
              module.getDependencies().compute(cachedNode, (key, old) -> merge(old, Set.of(TRANSITIVE),
                                                                               () -> EnumSet.noneOf(DependencyType.class)));
            }
            else {
              for (String aPackage : module.getRequiredPackages()) { // check node by "Required Packages" (if necessary)
                final Set<ModuleNode> nodes = packagesDeclaredInModules.getOrDefault(aPackage, Set.of());
                for (ModuleNode node : nodes) {
                  if (module.getDependencies().containsKey(node)) continue;
                  if (!cachedNode.equals(node)) continue;
                  module.getDependencies().computeIfAbsent(node, k -> Set.of());
                }
              }
            }
          }
        }
      }
      myProgressTracker.increment();
    }
    return modules;
  }
@NotNull
  private Set<ModuleNode> prepareModulesWithDependencies(@NotNull Map<String, Set<ModuleNode>> packagesDeclaredInModules)