public Set<PathFinder.Path> getRecursiveClosure(ToShapeId shape) {
        if (shape instanceof Shape) {
            return Collections.unmodifiableSet(recursiveShapes.getOrDefault(shape, Collections.emptySet()));
        }

        // If given an ID, we need to scan the recursive shapes to look for a matching ID.
        ShapeId id = shape.toShapeId();
        for (Map.Entry<Shape, Set<PathFinder.Path>> entry : recursiveShapes.entrySet()) {
            if (entry.getKey().getId().equals(id)) {
                return Collections.unmodifiableSet(entry.getValue());
            }
        }

        return Collections.emptySet();
    }
Gets the recursive closure of a given shape represented as
{@link PathFinder.Path} objects.

<p>The first element of each path is the given {@code shape},
and the last element of each path is the first shape that is
encountered a second time in the path (i.e., the point of
recursion).

@param shape Shape to get the recursive closures of.
@return The closures of the shape, or an empty {@code Set} if the shape is not recursive.
smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/TopologicalIndex.java