@NotNull
  public <T> MultiMap<T, T> mapParentToChildren(@NotNull final Collection<? extends T> nodes,
                                                @NotNull final Function<? super T, String> fileNameFunc) {

    final Collection<ProjectViewFileNestingService.NestingRule> rules = getNestingRules();
    if (rules.isEmpty()) return MultiMap.empty();

    // result that will contain number of separated parent-to-many-children sub-graphs
    MultiMap<T, T> parentToChildren = null;

    Set<T> allChildNodes = null; // helps to remove all outbound edges of a node that has inbound edge itself
    Map<Pair<String, ProjectViewFileNestingService.NestingRule>, Edge<T>> baseNameAndRuleToEdge = null; // temporary map for building edges

    for (T node : nodes) {
      final String fileName = fileNameFunc.apply(node);
      if (fileName == null) continue;

      for (ProjectViewFileNestingService.NestingRule rule : rules) {
        final Couple<Boolean> c = checkMatchingAsParentOrChild(rule, fileName);
        final boolean matchesParent = c.first;
        final boolean matchesChild = c.second;

        if (!matchesChild && !matchesParent) continue;

        if (baseNameAndRuleToEdge == null) {
          baseNameAndRuleToEdge = new HashMap<>();
          parentToChildren = new MultiMap<>();
          allChildNodes = new HashSet<>();
        }

        if (matchesParent) {
          final String baseName = fileName.substring(0, fileName.length() - rule.getParentFileSuffix().length());
          final Edge<T> edge = getOrCreateEdge(baseNameAndRuleToEdge, baseName, rule);
          edge.from = node;
          updateInfoIfEdgeComplete(parentToChildren, allChildNodes, edge);
        }

        if (matchesChild) {
          final String baseName = fileName.substring(0, fileName.length() - rule.getChildFileSuffix().length());
          final Edge<T> edge = getOrCreateEdge(baseNameAndRuleToEdge, baseName, rule);
          edge.to = node;
          updateInfoIfEdgeComplete(parentToChildren, allChildNodes, edge);
        }
      }
    }

    return parentToChildren == null ? MultiMap.empty() : parentToChildren;
  }
@NotNull
  public <T> MultiMap<T, T> mapParentToChildren(@NotNull final Collection<? extends T> nodes,
                                                @NotNull final Function<? super T, String> fileNameFunc)