Model transform(ModelTransformer transformer, Model model) {
        NeighborProvider reverse = NeighborProviderIndex.of(model).getReverseProvider();
        OperationIndex operationIndex = OperationIndex.of(model);

        List<Shape> updates = new ArrayList<>();
        List<Shape> toRemove = new ArrayList<>();
        for (OperationShape operation : model.getOperationShapes()) {
            StructureShape input = operationIndex.expectInputShape(operation);
            StructureShape updatedInput = createdUpdatedInput(model, operation, input, reverse);
            StructureShape output = operationIndex.expectOutputShape(operation);
            StructureShape updatedOutput = createdUpdatedOutput(model, operation, output, reverse);

            boolean inputChanged = !input.equals(updatedInput);
            boolean outputChanged = !output.equals(updatedOutput);

            if (!inputChanged && !outputChanged) {
                continue;
            }

            OperationShape.Builder builder = operation.toBuilder();
            if (inputChanged) {
                LOGGER.fine(() -> String.format("Updating operation input of %s from %s to %s",
                        operation.getId(),
                        input.getId(),
                        updatedInput.getId()));
                updates.add(updatedInput);
                builder.input(updatedInput);
                // If the ID changed and the original is no longer referenced, then remove it.
                boolean idChanged = !input.getId().equals(updatedInput.getId());
                if (idChanged && isSingularReference(reverse, input, operation)) {
                    toRemove.add(input);
                    LOGGER.fine("Removing now unused input shape " + input.getId());
                }
            }
            if (outputChanged) {
                LOGGER.fine(() -> String.format("Updating operation output of %s from %s to %s",
                        operation.getId(),
                        output.getId(),
                        updatedOutput.getId()));
                updates.add(updatedOutput);
                builder.output(updatedOutput);
                // If the ID changed and the original is no longer referenced, then remove it.
                boolean idChanged = !output.getId().equals(updatedOutput.getId());
                if (idChanged && isSingularReference(reverse, output, operation)) {
                    toRemove.add(output);
                    LOGGER.fine("Removing now unused output shape " + output.getId());
                }
            }
            updates.add(builder.build());
        }

        // Remove no longer referenced shapes.
        Model result = transformer.removeShapes(model, toRemove);

        // Replace the operations and add new shapes.
        return transformer.replaceShapes(result, updates);
    }
@see ModelTransformer#createDedicatedInputAndOutput(Model, String, String)
smithy-model/src/main/java/software/amazon/smithy/model/transform/CreateDedicatedInputAndOutput.java