private Set<Shape> getUpdatedContainers(Model model, Collection<Shape> shouldReplace) {
        // Determine what shapes being updated are members, and group them by their container shapes.
        Map<Shape, List<MemberShape>> containerToMemberMapping = new HashMap<>();
        for (Shape shape : shouldReplace) {
            shape.asMemberShape().ifPresent(member -> {
                findMostUpToDateShape(member.getContainer(), model, shouldReplace).ifPresent(container -> {
                    // Ignore members that are already a current member of a shape.
                    if (!isMemberPresent(member, container)) {
                        containerToMemberMapping.computeIfAbsent(container, c -> new ArrayList<>()).add(member);
                    }
                });
            });
        }

        Set<Shape> containersToUpdate = new HashSet<>(containerToMemberMapping.size());

        // Update the containers with members.
        for (Map.Entry<Shape, List<MemberShape>> entry : containerToMemberMapping.entrySet()) {
            Shape container = entry.getKey();
            List<MemberShape> members = entry.getValue();
            AbstractShapeBuilder<?, ?> builder = Shape.shapeToBuilder(container);
            for (MemberShape member : members) {
                builder.addMember(member);
            }
            containersToUpdate.add(builder.build());
        }

        return containersToUpdate;
    }
Replaces shapes while ensuring that the transformed model is in a
consistent state.

<p>This transformer accounts for the following scenarios:

<ul>
    <li>When a member is modified, ensures that its containing shape
    references the new member.</li>
    <li>When an aggregate shape is modified, ensures that all members are
    updated in the model.</li>
    <li>When a member is removed from a structure or union,
    ensures that the member is removed from the model.</li>
    <li>When a mixin is updated, ensures that all shapes that use the
    mixin are updated.</li>
</ul>

<p>Only shapes that are not currently in a model or shapes that are
different than the existing shape in a model are inserted into a
transformed model.

<p>When updates are made both to a container shape and to a member owned
by the container shape, the member updates takes precedent over any
updated made to the old member referenced by the container (e.g., if you
update a structure and change one of the members of the structure without
also updating the member in the model *and* you update a member in
the model, the member in the model will overwrite the member referenced
by the structure).

<p>This transformer only supports replacing shapes if the previous shape
and new shape are of the same type. Any replacements encountered that
attempt to change the type of a shape will throw an exception.
smithy-model/src/main/java/software/amazon/smithy/model/transform/ReplaceShapes.java