private static void removeLosers()

in maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java [299:387]


    private static void removeLosers(State state) {
        ConflictItem winner = state.conflictCtx.winner;
        String winnerArtifactId = ArtifactIdUtils.toId(winner.node.getArtifact());
        List<DependencyNode> previousParent = null;
        ListIterator<DependencyNode> childIt = null;
        HashSet<String> toRemoveIds = new HashSet<>();
        for (ConflictItem item : state.items) {
            if (item == winner) {
                continue;
            }
            if (item.parent != previousParent) {
                childIt = item.parent.listIterator();
                previousParent = item.parent;
            }
            while (childIt.hasNext()) {
                DependencyNode child = childIt.next();
                if (child == item.node) {
                    // NONE: just remove it and done
                    if (Verbosity.NONE == state.verbosity) {
                        childIt.remove();
                        break;
                    }

                    // STANDARD: doing extra bookkeeping to select "which nodes to remove"
                    if (Verbosity.STANDARD == state.verbosity) {
                        String childArtifactId = ArtifactIdUtils.toId(child.getArtifact());
                        // if two IDs are equal, it means "there is nearest", not conflict per se.
                        // In that case we do NOT allow this child to be removed (but remove others)
                        // and this keeps us safe from iteration (and in general, version) ordering
                        // as we explicitly leave out ID that is "nearest found" state.
                        //
                        // This tackles version ranges mostly, where ranges are turned into list of
                        // several nodes in collector (as many were discovered, ie. from metadata), and
                        // old code would just "mark" the first hit as conflict, and remove the rest,
                        // even if rest could contain "more suitable" version, that is not conflicting/diverging.
                        // This resulted in verbose mode transformed tree, that was misrepresenting things
                        // for dependency convergence calculations: it represented state like parent node
                        // depends on "wrong" version (diverge), while "right" version was present (but removed)
                        // as well, as it was contained in parents version range.
                        if (!Objects.equals(winnerArtifactId, childArtifactId)) {
                            toRemoveIds.add(childArtifactId);
                        }
                    }

                    // FULL: just record the facts
                    DependencyNode loser = new DefaultDependencyNode(child);
                    loser.setData(NODE_DATA_WINNER, winner.node);
                    loser.setData(
                            NODE_DATA_ORIGINAL_SCOPE, loser.getDependency().getScope());
                    loser.setData(
                            NODE_DATA_ORIGINAL_OPTIONALITY,
                            loser.getDependency().isOptional());
                    loser.setScope(item.getScopes().iterator().next());
                    loser.setChildren(Collections.emptyList());
                    childIt.set(loser);
                    item.node = loser;
                    break;
                }
            }
        }

        // 2nd pass to apply "standard" verbosity: leaving only 1 loser, but with care
        if (Verbosity.STANDARD == state.verbosity && !toRemoveIds.isEmpty()) {
            previousParent = null;
            for (ConflictItem item : state.items) {
                if (item == winner) {
                    continue;
                }
                if (item.parent != previousParent) {
                    childIt = item.parent.listIterator();
                    previousParent = item.parent;
                }
                while (childIt.hasNext()) {
                    DependencyNode child = childIt.next();
                    if (child == item.node) {
                        String childArtifactId = ArtifactIdUtils.toId(child.getArtifact());
                        if (toRemoveIds.contains(childArtifactId)
                                && relatedSiblingsCount(child.getArtifact(), item.parent) > 1) {
                            childIt.remove();
                        }
                        break;
                    }
                }
            }
        }

        // there might still be losers beneath the winner (e.g. in case of cycles)
        // those will be nuked during future graph walks when we include the winner in the recursion
    }