Set<Shape> markAndSweep(Model model) {
        NeighborProvider reverseNeighbors = NeighborProvider.reverse(model);
        MarkerContext context = new MarkerContext(reverseNeighbors, model, sweepFilter);

        int currentSize;
        do {
            currentSize = context.getMarkedForRemoval().size();
            marker.accept(context);
            // Find shapes that are only referenced by a shape that has been marked for removal.
            model.shapes().filter(shape -> !shape.isMemberShape()).forEach(shape -> {
                if (!context.getMarkedForRemoval().contains(shape)) {
                    Set<Shape> targetedFrom = context.getTargetedFrom(shape);
                    if (!targetedFrom.isEmpty()) {
                        targetedFrom.removeAll(context.getMarkedForRemoval());
                        if (targetedFrom.isEmpty()) {
                            context.markShape(shape);
                        }
                    }
                }
            });
        } while (currentSize != context.getMarkedForRemoval().size());

        return context.getMarkedForRemoval();
    }
Performs a garbage collection style cleanup of a model by removing
unreferenced shapes based on a custom {@code marker} function.

<p>The marker function is invoked at the start of each round and passed
a context object. The marker can query the context object and mark shapes
as needing to be removed. The MarkAndSweep then finds all shapes
that have targets to them but is only targeted by shapes that have been
marked for removal. These matching shapes are then marked for removal as
well, potentially freeing up other shapes to be marked for removal in the
next round. This process continues until no new shapes are marked in a
round.
smithy-model/src/main/java/software/amazon/smithy/model/transform/MarkAndSweep.java