private void addRelationships(Shape traitDef, NodeQuery query) {
        model.getShapesWithTrait(traitDef.getId()).forEach(shape -> {
            Trait trait = shape.findTrait(traitDef.getId()).get(); // We already know the shape has the trait.
            Node node = trait.toNode();
            // Invalid shape ids are handled by the idRef trait validator, so ignore them here.
            query.execute(node)
                    .forEach(n -> n.asStringNode()
                            .flatMap(StringNode::asShapeId)
                            .flatMap(model::getShape)
                            .map(referenced -> Relationship.create(shape, RelationshipType.ID_REF, referenced))
                            .ifPresent(rel -> relationships
                                    .computeIfAbsent(rel.getShape().getId(), id -> new HashSet<>())
                                    .add(rel)));
        });
    }
Finds all {@link RelationshipType#ID_REF} relationships in a model.

<p>This works by finding all paths from {@link TraitDefinition} shapes
to shapes with {@link IdRefTrait}, then using those paths to search
the node values of each application of the trait to extract the {@link ShapeId}
value. Because we don't have a fixed set of traits known to potentially have
idRef members, this has to be done dynamically.
smithy-model/src/main/java/software/amazon/smithy/model/neighbor/IdRefShapeRelationships.java