What's New in Version 0.8.0

Proof that your feedback does not fall on deaf ears - version 0.8.0 is out with some highly requested features.

First off, all you trail blazers out there will be pleased to hear that Periphery now supports Xcode 9’s new build system. It’ll be the default build system starting from Xcode 10, so I thought it best to get support in as early as possible. If you haven’t tried it out yet, maybe now is the time? You can carry on using Periphery exactly as you do with the current build system.


Previous releases didn’t support analyzing XCTest targets. My thinking was - “Code that’s only being used by a test case is code you don’t need.”. While that point of view is correct most of the time, there are a few scenarios where it’s perfectly valid to keep around some unused code (though hopefully only temporarily!). You can now pass test targets to the --targets option and they’ll be analyzed just like the others. Oh, and don’t worry - Periphery knows that all your XCTestCase subclass and test methods are in use.


Licenses can now be activated non-interactively, with a single command: periphery activate --email <email> --key <license key>. A welcome addition for those automating their use of Periphery.


Now, the coolest feature of this release - the diagnosis console! If you’ve ever questioned why Periphery didn’t report that a declaration was unused - yet you expected it to be - the diagnosis console can tell you the reason it’s still in use. Let’s use Periphery itself as an example. With the new --diagnose option, you’ll be greeted by a prompt after the results:

Welcome to the diagnosis console.
Type 'help' for instructions, ^C to exit.
>

The console has two commands: search and inspect. search allows you to search for declarations by name, e.g:

> search process
Found 1 declaration containing 'process':

[function.method.instance, 'process(_:)', private, [private], 's:12PeripheryKit16DiagnosisConsoleC7process33', DiagnosisConsole.swift:27:18]

Periphery’s code has a single declaration with a name containing ‘process’, and it’s the process(_:) method that handles input in the diagnosis console. Each declaration is represented as an array of details:

[<kind>, <name>, <accessibility>, <attributes>, <LLVM Unified Symbol Resolution (USR)>, <source location>]

We can now inspect this declaration using its unique USR.

> inspect 's:12PeripheryKit16DiagnosisConsoleC7process33'

Declaration hierarchy:

[function.method.instance, 'process(_:)', private, [private], 's:12PeripheryKit16DiagnosisConsoleC7process33', DiagnosisConsole.swift:27:18]
·· [class, 'DiagnosisConsole', public, [public], 's:12PeripheryKit16DiagnosisConsoleC', DiagnosisConsole.swift:3:14]

Active references:

[function.method.instance, 'process(_:)', 's:12PeripheryKit16DiagnosisConsoleC7process33', nil, DiagnosisConsole.swift:18:17]

We can see there’s a single reference to process(_:) at DiagnosisConsole.swift line 18, which happens to be:

17: if let command = readLine(strippingNewline: true) {
18:     process(command)
19: } else {

So we can see that the console is a useful tool for inspecting all active references to a particular declaration. However, Periphery must consider some declarations as being in use, even if there may not be any active references to them, i.e they are ‘retained’. The console will explain the reason:

> inspect 's:9periphery11HelpCommandV'
Declaration 'HelpCommand' does not have any active references, though it is retained because:
declaration is 'public' and the '--retain-public' option is in effect. Disable this behavior with '--no-retain-public'.

> inspect 'c:@M@periphery@objc(cs)ObjectInspector(im)'
Declaration 'ObjectInspector' does not have any active references, though it is retained because:
declaration is accessible by Objective-C and the '--retain-objc-annotated' option is in effect. Disable this behavior with '--no-retain-objc-annotated'.

> inspect 's:9periphery7versionyyF'
Declaration 'version()' does not have any active references, though it is retained because:
declaration is declared in main.swift.

> inspect 'c:@M@PeripheryKitTests@objc(cs)RetentionTest(im)testRetainedProtocolDoesNotRetainUnusedClass'
Declaration 'testRetainedProtocolDoesNotRetainUnusedClass()' does not have any active references, though it is retained because:
declaration is an XCTest test case or test method.

This is a pretty powerful feature, and we hope it can give you some deeper insight into the structure of your code.


Along with a couple of bug fixes, version 0.8.0 is the biggest release to date. The next few releases will focus on making Periphery even more convenient to use in Continuous Integration environments, watch this space!

To upgrade Periphery:

brew cask upgrade periphery