Skip to content

Type used only as nested struct property falsely reported unused #1062

@danwood

Description

@danwood

Describe the bug

Periphery falsely reports a type as unused when it is only referenced as a property type inside a nested struct. The type is used -- removing it would break compilation -- but Periphery does not follow property type references on child declarations during its used-declaration marking pass.

For example, consider a view model containing a nested section struct, where the section references an item type:

struct RiderItem: Identifiable, Hashable {
    let id: UUID
    let name: String
}

public struct RiderViewModel {
    struct RiderSection: Identifiable, Hashable {
        let id: UUID
        var equipment: [RiderItem]
    }

    var sections: [RiderSection] = []

    public mutating func addSection() {
        sections.append(RiderSection(id: UUID(), equipment: []))
    }
}

Periphery reports RiderItem as unused, even though RiderSection.equipment depends on it. The issue occurs because RiderItem is only referenced as a property type (var equipment: [RiderItem]) within the nested RiderSection struct. Swift's indexer associates that type reference with the property declaration itself, not with the containing struct. When Periphery marks RiderViewModel as used, it walks references and related declarations but never descends into child declarations to discover the property type reference to RiderItem.

The same problem applies more broadly: any type referenced exclusively as a property type on a child declaration of a used type will be missed.

Reproduction

  1. Create a Swift package or Xcode project containing the code above.
  2. Ensure RiderViewModel is public (or otherwise retained).
  3. Run periphery scan.
  4. Observe that RiderItem is reported as unused.

Environment

Apple Swift version 6.2.3 (swiftlang-6.2.3.3.21 clang-1700.6.3.2)
Xcode 26.2 (Build version 17C52)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions