Periphery Documentation
repository·master·Indexed 27 days ago
https://github.com/peripheryapp/peripheryPeriphery 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.
What's inside Periphery
- 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.
Run the guided setup for Periphery
masterTo begin a guided setup that detects your project type and configures initial options, navigate to your project directory and run the
scancommand with the--setupflag. Periphery will prompt you with questions and then provide/execute the full scan command.periphery scan --setupRun Periphery in Continuous Integration (CI)
masterTo speed up CI, you can skip the build phase if your pipeline has already built the project by using the
--skip-buildoption. 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(orIndex.noindex/DataStorefor Xcode 14+). - SwiftPM: By default, Periphery looks in
.build/debug/index/store. If you run Periphery immediately afterswift test, you may not need to specify the path, but it is safer to provide it explicitly if the default location differs.
- Xcode: The index store is located in
Use the `scan` command
masterThe
scancommand 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
--schemesoption 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-publicoption 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- 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
Override result kind and location for generated code
masterWhen working with generated code that is too low-level to report accurately, you can override the reported
kindandlocationusing a comment command. Thelocationformat isfile: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() {}Integrate Periphery with Xcode
masterTo run Periphery directly from Xcode, follow these steps:
- Create an Aggregate Target: In your project, add a new target of type Other -> Aggregate (e.g., named "Periphery").
- 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
peripheryand include the--format xcodeoption 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").
- Tip: Use the absolute path to
- Disable User Script Sandboxing: In the Periphery target's Build Settings, set
ENABLE_USER_SCRIPT_SANDBOXINGtoNo. This is required to allow Periphery to access the index store and source files. - 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.
Use comment commands to ignore unused code
masterYou can use specific comment commands to exclude declarations from Periphery's analysis:
- Ignore a declaration and its descendants: Place
// periphery:ignoreon 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:allat 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) }- Ignore a declaration and its descendants: Place
Install Periphery
masterPeriphery can be installed using Homebrew, Mint, or Bazel depending on your environment.Install Periphery via Bazel
masterTo use Periphery with Bazel, add the following dependency to your
MODULE.bazelfile:bazel_dep(name = "periphery", version = "<version>", dev_dependency = True) use_repo(use_extension("@periphery//bazel:generated.bzl", "generated"), "periphery_generated")Handle unused function parameters in protocols and overrides
masterPeriphery 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
fatalErroror 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-paramsoption.--retain-unused-protocol-func-paramsAudit unused code within SPI (System Programming Interface)
masterWhen using
--retain-publicfor 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 Internalwill retain regular public declarations and@_spi(Testing)declarations, but will check@_spi(Internal)declarations for unused code.--retain-public --no-retain-spi InternalConfigure external XCTestCase subclasses
masterClasses inheriting from
XCTestCaseare 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