Periphery Documentation

repository·master·Indexed 27 days ago

https://github.com/peripheryapp/periphery

Periphery is a tool for identifying unused code in Swift projects by analyzing the project's relational structure via an index store. It detects unreferenced code, redundant protocols, assign-only properties, and redundant public accessibility. It supports integration with Xcode, Swift Package Manager, and Bazel, and provides options for handling Objective-C compatibility, Codable/Equatable/Hashable synthesis, and SPI auditing.

Tokens
4.1K
Snippets
15
Records
30
Agent score
91%

What's inside Periphery

  1. Identify redundant protocols

    master
    Periphery detects redundant protocols. A protocol is considered redundant if it is only used for conformance by objects but is never used as an existential type or to specialize a generic method/class. In such cases, the protocol and its redundant conformances can be removed.
  2. Run the guided setup for Periphery

    master

    To begin a guided setup that detects your project type and configures initial options, navigate to your project directory and run the scan command with the --setup flag. Periphery will prompt you with questions and then provide/execute the full scan command.

    periphery scan --setup
  3. Run Periphery in Continuous Integration (CI)

    master

    To speed up CI, you can skip the build phase if your pipeline has already built the project by using the --skip-build option. When doing this, you must provide the location of the index store using --index-store-path.

    • Xcode: The index store is located in DerivedData/YourProject-xxx/Index/DataStore (or Index.noindex/DataStore for Xcode 14+).
    • SwiftPM: By default, Periphery looks in .build/debug/index/store. If you run Periphery immediately after swift test, you may not need to specify the path, but it is safer to provide it explicitly if the default location differs.
  4. Use the `scan` command

    master

    The scan command is the primary entry point for Periphery. It works by building your project to generate an "index store", building an in-memory relational graph of your declarations, and traversing that graph to identify unreferenced code.

    Important Considerations:

    • Build Targets: Periphery only sees information for source files in the build targets compiled during the build phase. For Xcode projects, ensure you use the --schemes option to include all relevant targets. For Swift packages, all targets are built automatically.
    • Standalone Frameworks: If your project contains standalone frameworks that are not consumed by an application, use the --retain-public option to prevent Periphery from marking all public declarations as unused.
    • Objective-C: For mixed Swift and Objective-C projects, be aware of specific implications regarding analysis results.
    periphery scan
  5. Override result kind and location for generated code

    master

    When working with generated code that is too low-level to report accurately, you can override the reported kind and location using a comment command. The location format is file:line:column (line and column default to 1 if omitted). Relative paths are assumed to be relative to the project root.

    // periphery:override kind="MyCustomThing" location="path/to/file.swift:42:1"
    func generatedFunction() {}
  6. Integrate Periphery with Xcode

    master

    To run Periphery directly from Xcode, follow these steps:

    1. Create an Aggregate Target: In your project, add a new target of type Other -> Aggregate (e.g., named "Periphery").
    2. Add a Run Script Build Phase: In the new target's Build Phases, add a Run Script phase. Paste your Periphery command.
      • Tip: Use the absolute path to periphery and include the --format xcode option so Xcode can parse the results.
      • Tip: If your project requires specific destinations, pass them via -- (e.g., periphery scan ... -- -destination "generic/platform=iOS Simulator").
    3. Disable User Script Sandboxing: In the Periphery target's Build Settings, set ENABLE_USER_SCRIPT_SANDBOXING to No. This is required to allow Periphery to access the index store and source files.
    4. Run: Select the new scheme in the Xcode scheme dropdown and hit Run. Mark the scheme as Shared if you want to check it into source control for your team.
  7. Use comment commands to ignore unused code

    master

    You can use specific comment commands to exclude declarations from Periphery's analysis:

    • Ignore a declaration and its descendants: Place // periphery:ignore on the line directly above the declaration.
    • Ignore specific function parameters: Use // periphery:ignore:parameters <param1>,<param2> above the function.
    • Ignore an entire file: Place // periphery:ignore:all at the very top of the file (above imports).
    • Add explanations: Append a hyphen to any command to include a trailing comment (e.g., // periphery:ignore - explanation).

    Example of ignoring specific parameters:

    // periphery:ignore:parameters unusedOne,unusedTwo
    func someFunc(used: String, unusedOne: String, unusedTwo: String) {
        print(used)
    }
  8. Install Periphery via Bazel

    master

    To use Periphery with Bazel, add the following dependency to your MODULE.bazel file:

    bazel_dep(name = "periphery", version = "<version>", dev_dependency = True)
    use_repo(use_extension("@periphery//bazel:generated.bzl", "generated"), "periphery_generated")
  9. Handle unused function parameters in protocols and overrides

    master

    Periphery identifies unused function parameters in protocols and overridden methods. A parameter is only reported as unused if it is unused in all implementations (for protocols) or in the base function and all overriding functions (for overrides).

    Note: Unused parameters in functions that only call fatalError or parameters in protocols/classes defined in foreign modules (e.g., Foundation) are automatically ignored.

    To prevent reporting unused parameters from protocols and their conforming functions, use the --retain-unused-protocol-func-params option.

    --retain-unused-protocol-func-params
  10. Audit unused code within SPI (System Programming Interface)

    master

    When using --retain-public for framework projects, all public declarations (including those marked with @_spi) are retained by default. To audit specific SPIs for unused code while still retaining the rest of the public API, use --no-retain-spi.

    Example: --retain-public --no-retain-spi Internal will retain regular public declarations and @_spi(Testing) declarations, but will check @_spi(Internal) declarations for unused code.

    --retain-public --no-retain-spi Internal
  11. Configure external XCTestCase subclasses

    master

    Classes inheriting from XCTestCase are automatically retained. If your test base class (e.g., UnitTestCase) resides in a target that Periphery does not scan, you must explicitly tell Periphery to treat it as a test case class.

    --external-test-case-classes UnitTestCase