Giter Site home page Giter Site logo

periphery's Introduction

Periphery
Periphery

A tool to identify unused code in Swift projects.

Now I am become Delete, the destroyer of codes.



Contents

Installation

brew install peripheryapp/periphery/periphery
mint install peripheryapp/periphery

How To Use

The scan Command

The scan command is Periphery's primary function. To begin a guided setup, simply change to your project directory and run:

periphery scan --setup

Guided setup only works for Xcode and SwiftPM projects, to use Periphery with non-Apple build systems such as Bazel, see Build Systems.

After answering a few questions, Periphery will print out the full scan command and execute it.

The guided setup is only intended for introductory purposes, once you are familiar with Periphery you can try some more advanced options, all of which can be seen with periphery help scan.

To get coherent results from Periphery, it's crucial to understand the implications of the build targets you choose to analyze. For example, imagine a project consisting of three targets: App, Lib and Tests. The App target imports Lib, and the Tests targets imports both App and Lib. If you were to provide all three to the --targets option then Periphery will be able to analyze your project as a whole. However, if you only choose to analyze App and Lib, but not Tests, Periphery may report some instances of unused code that are only referenced by Tests. Therefore when you suspect Periphery has provided an incorrect result, it's important to consider the targets that you have chosen to analyze.

If your project consists of one or more standalone frameworks that do not also contain some kind of application that consume their interfaces, then you'll need to tell Periphery to assume that all public declarations are in fact used by including the --retain-public option.

For projects that are mixed Objective-C & Swift, it's highly recommend you read about the implications this can have on your results.

Configuration

Once you've settled upon the appropriate options for your project, you may wish to persist them in a YAML configuration file. The simplest way to achieve this is to run Periphery with the --verbose option. Near the beginning of the output you will see the [configuration:begin] section with your configuration formatted as YAML below. Copy & paste the configuration into .periphery.yml in the root of your project folder. You can now simply run periphery scan and the YAML configuration will be used.

How It Works

Periphery first builds your project. For Xcode projects the schemes provided via the --schemes option are built using xcodebuild. For Swift Package Manager projects, the individual targets provided via the --targets option are built using swift build. The Swift compiler employs a technique called index-while-building to populate an index store that contains information about the structure of your project's source code.

After your project is built, Periphery performs an indexing phase. For every source file that is a member of the targets provided via the --targets option, Periphery obtains its structural information from the index store and builds its own internal graph representation of your project. Periphery also analyzes each file's abstract syntax tree (AST) to fill in some details not provided by the index store.

Once indexing is complete, Periphery analyzes the graph to identify unused code. This phase consists of a number of steps that mutate the graph to make it easier to identify specific scenarios of unused code. The final step walks the graph from its roots to identify declarations that are no longer referenced.

Analysis

The goal of Periphery is to report instances of unused declarations. A declaration is a class, struct, protocol, function, property, constructor, enum, typealias, associatedtype, etc. As you'd expect, Periphery is able to identify simple unreferenced declarations, e.g a class that is no longer used anywhere in your codebase.

Periphery can also identify more advanced instances of unused code. The following section explains these in detail.

Function Parameters

Periphery can identify unused function parameters. Instances of unused parameters can also be identified in protocols and their conforming declarations, as well as parameters in overridden methods. Both of these scenarios are explained further below.

Protocols

An unused parameter of a protocol function will only be reported as unused if the parameter is also unused in all implementations.

protocol Greeter {
    func greet(name: String)
    func farewell(name: String) // 'name' is unused
}

class InformalGreeter: Greeter {
    func greet(name: String) {
        print("Sup " + name + ".")
    }

    func farewell(name: String) { // 'name' is unused
      print("Cya.")
    }
}

Tip

You can ignore all unused parameters from protocols and conforming functions with the --retain-unused-protocol-func-params option.

Overrides

Similar to protocols, parameters of overridden functions are only reported as unused if they're also unused in the base function and all overriding functions.

class BaseGreeter {
    func greet(name: String) {
        print("Hello.")
    }

    func farewell(name: String) { // 'name' is unused
        print("Goodbye.")
    }
}

class InformalGreeter: BaseGreeter {
    override func greet(name: String) {
        print("Sup " + name + ".")
    }

    override func farewell(name: String) { // 'name' is unused
        print("Cya.")
    }
}

Foreign Protocols & Classes

Unused parameters of protocols or classes defined in foreign modules (e.g Foundation) are always ignored, since you do not have access to modify the base function declaration.

fatalError Functions

Unused parameters of functions that simply call fatalError are also ignored. Such functions are often unimplemented required initializers in subclasses.

class Base {
    let param: String

    required init(param: String) {
        self.param = param
    }
}

class Subclass: Base {
    init(custom: String) {
        super.init(param: custom)
    }

    required init(param: String) {
        fatalError("init(param:) has not been implemented")
    }
}

Protocols

A protocol which is conformed to by an object is not truly used unless it's also used as an existential type, or to specialize a generic method/class. Periphery is able to identify such redundant protocols whether they are conformed to by one, or even multiple objects.

protocol MyProtocol { // 'MyProtocol' is redundant
    func someMethod()
}

class MyClass1: MyProtocol { // 'MyProtocol' conformance is redundant
    func someMethod() {
        print("Hello from MyClass1!")
    }
}

class MyClass2: MyProtocol { // 'MyProtocol' conformance is redundant
    func someMethod() {
        print("Hello from MyClass2!")
    }
}

let myClass1 = MyClass1()
myClass1.someMethod()

let myClass2 = MyClass2()
myClass2.someMethod()

Here we can see that despite both implementations of someMethod are called, at no point does an object take on the type of MyProtocol. Therefore the protocol itself is redundant, and there's no benefit from MyClass1 or MyClass2 conforming to it. We can remove MyProtocol along with each redundant conformance, and just keep someMethod in each class.

Just like a normal method or property of a object, individual properties and methods declared by your protocol can also be identified as unused.

protocol MyProtocol {
    var usedProperty: String { get }
    var unusedProperty: String { get } // 'unusedProperty' is unused
}

class MyConformingClass: MyProtocol {
    var usedProperty: String = "used"
    var unusedProperty: String = "unused" // 'unusedProperty' is unused
}

class MyClass {
    let conformingClass: MyProtocol

    init() {
        conformingClass = MyConformingClass()
    }

    func perform() {
        print(conformingClass.usedProperty)
    }
}

let myClass = MyClass()
myClass.perform()

Here we can see that MyProtocol is itself used, and cannot be removed. However, since unusedProperty is never called on MyConformingClass, Periphery is able to identify that the declaration of unusedProperty in MyProtocol is also unused and can be removed along with the unused implementation of unusedProperty.

Enumerations

Along with being able to identify unused enumerations, Periphery can also identify individual unused enum cases. Plain enums that are not raw representable, i.e that don't have a String, Character, Int or floating-point value type can be reliably identified. However, enumerations that do have a raw value type can be dynamic in nature, and therefore must be assumed to be used.

Let's clear this up with a quick example:

enum MyEnum: String {
    case myCase
}

func someFunction(value: String) {
    if let myEnum = MyEnum(rawValue: value) {
        somethingImportant(myEnum)
    }
}

There's no direct reference to the myCase case, so it's reasonable to expect it might no longer be needed, however if it were removed we can see that somethingImportant would never be called if someFunction were passed the value of "myCase".

Assign-only Properties

Properties that are assigned but never used are identified as such, e.g:

class MyClass {
    var assignOnlyProperty: String // 'assignOnlyProperty' is assigned, but never used

    init(value: String) {
        self.assignOnlyProperty = value
    }
}

In some cases this may be the intended behavior, therefore you have a few options available to silence such results:

  • Retain individual properties using Comment Commands.
  • Retain all assign-only properties by their type with --retain-assign-only-property-types. Given types must match their exact usage in the property declaration (sans optional question mark), e.g String, [String], Set<String>. Periphery is unable to resolve inferred property types, therefore in some instances you may need to add explicit type annotations to your properties.
  • Disable assign-only property analysis entirely with --retain-assign-only-properties.

Redundant Public Accessibility

Declarations that are marked public yet are not referenced from outside their home module, are identified as having redundant public accessibility. In this scenario, the public annotation can be removed from the declaration. Removing redundant public accessibility has a couple of benefits:

This analysis can be disabled with --disable-redundant-public-analysis.

Unused Imports

Periphery can detect unused imports of targets it has scanned, i.e. those specified with the --targets argument. It cannot detect unused imports of other targets because the Swift source files are unavailable and uses of @_exported cannot be observed. @_exported is problematic because it changes the public interface of a target such that the declarations exported by the target are no longer necessarily declared by the imported target. For example, the Foundation target exports Dispatch, among other targets. If any given source file imports Foundation and references DispatchQueue but no other declarations from Foundation, then the Foundation import cannot be removed as it would also make the DispatchQueue type unavailable. To avoid false positives, therefore, Periphery only detects unused imports of targets it has scanned.

Periphery will likely produce false positives for targets with mixed Swift and Objective-C, as Periphery cannot scan the Objective-C files. It is recommended therefore to disable unused import detection for projects with a significant amount of Objective-C, or manually exclude the mixed language targets from the results.

Objective-C

Periphery cannot analyze Objective-C code since types may be dynamically typed.

By default Periphery does not assume that declarations accessible by the Objective-C runtime are in use. If your project is a mix of Swift & Objective-C, you can enable this behavior with the --retain-objc-accessible option. Swift declarations that are accessible by the Objective-C runtime are those that are explicitly annotated with @objc or @objcMembers, and classes that inherit NSObject either directly or indirectly via another class.

Alternatively, the --retain-objc-annotated can be used to only retain declarations that are explicitly annotated with @objc or @objcMembers. Types that inherit NSObject are not retained unless they have the explicit annotations. This option may uncover more unused code, but with the caveat that some of the results may be incorrect if the declaration is in fact used in Objective-C code. To resolve these incorrect results you must add an @objc annotation to the declaration.

Codable

Swift synthesizes additional code for Codable types that is not visible to Periphery, and can result in false positives for properties not directly referenced from non-synthesized code. If your project contains many such types, you can retain all properties on Codable types with --retain-codable-properties. Alternatively, you can retain properties only on Encodable types with --retain-encodable-properties.

If Codable conformance is declared by a protocol in an external module not scanned by Periphery, you can instruct Periphery to identify the protocols as Codable with --external-codable-protocols "ExternalProtocol".

XCTestCase

Any class that inherits XCTestCase is automatically retained along with its test methods. However, when a class inherits XCTestCase indirectly via another class, e.g UnitTestCase, and that class resides in a target that isn't scanned by Periphery, you need to use the --external-test-case-classes UnitTestCase option to instruct Periphery to treat UnitTestCase as an XCTestCase subclass.

Interface Builder

If your project contains Interface Builder files (such as storyboards and XIBs), Periphery will take these into account when identifying unused declarations. However, Periphery currently only identifies unused classes. This limitation exists because Periphery does not yet fully parse Interface Builder files (see issue #212). Due to Periphery's design principle of avoiding false positives, it is assumed that if a class is referenced in an Interface Builder file, all of its IBOutlets and IBActions are used, even if they might not be in reality. This approach will be revised to accurately identify unused IBActions and IBOutlets once Periphery gains the capability to parse Interface Builder files.

Comment Commands

For whatever reason, you may want to keep some unused code. Source code comment commands can be used to ignore specific declarations, and exclude them from the results.

An ignore comment command can be placed directly on the line above any declaration to ignore it, and all descendent declarations:

// periphery:ignore
class MyClass {}

You can also ignore specific unused function parameters:

// periphery:ignore:parameters unusedOne,unusedTwo
func someFunc(used: String, unusedOne: String, unusedTwo: String) {
    print(used)
}

The // periphery:ignore:all command can be placed at the top of the source file to ignore the entire contents of the file. Note that the comment must be placed above any code, including import statements.

Comment commands also support trailing comments following a hyphen so that you can include an explanation on the same line:

// periphery:ignore - explanation of why this is necessary
class MyClass {}

Xcode Integration

Before setting up Xcode integration, we highly recommend you first get Periphery working in a terminal, as you will be using the exact same command via Xcode.

Step 1: Create an Aggregate Target

Select your project in the Project Navigator and click the + button at the bottom left of the Targets section. Select Cross-platform and choose Aggregate. Hit Next.

Step 1

Choose a name for the new target, e.g "Periphery" or "Unused Code".

Step 2

Step 2: Add a Run Script Build Phase

In the Build Phases section click the + button to add a new Run Script phase.

Step 3

In the shell script window enter the Periphery command. Be sure to include the --format xcode option.

Step 4

Step 3: Select & Run

You're ready to roll. You should now see the new scheme in the dropdown. Select it and hit run.

Tip

If you'd like others on your team to be able to use the scheme, you'll need to mark it as Shared. This can be done by selecting Manage Schemes... and selecting the Shared checkbox next to the new scheme. The scheme definition can now be checked into source control.

Step 5

Excluding Files

Both exclusion options described below accept a Bash v4 style path glob, either absolute or relative to your project directory. You can delimit multiple globs with a space, e.g --option "Sources/Single.swift" "**/Generated/*.swift" "**/*.{xib,storyboard}".

Excluding Results

To exclude the results from certain files, pass the --report-exclude <globs> option to the scan command.

Excluding Indexed Files

To exclude files from being indexed, pass the --index-exclude <globs> option to the scan command. Excluding files from the index phase means that any declarations and references contained within the files will not be seen by Periphery. Periphery will be behave as if the files do not exist. For example, this option can be used to exclude generated code that holds references to non-generated code, or exclude all .xib and .storyboard files that hold references to code.

Retaining File Declarations

To retain all declarations in files, pass the --retain-files <globs> option to the scan command. This option is equivalent to adding a // periphery:ignore:all comment command at the top of each file.

Continuous Integration

When integrating Periphery into a CI pipeline, you can potentially skip the build phase if your pipeline has already done so, e.g to run tests. This can be achieved using the --skip-build option. However, you also need to tell Periphery the location of the index store using --index-store-path. This location is dependent on your project type.

Note that when using --skip-build and --index-store-path it's vital that the index store contains data for all of the targets you specify via --targets. For example, if your pipeline previously built the targets 'App' and 'Lib', the index store will only contain data for the files in those targets. You cannot then instruct Periphery to scan additional targets, e.g 'Extension', or 'UnitTests'.

Xcode

The index store generated by xcodebuild exists in DerivedData at a location dependent on your project, e.g ~/Library/Developer/Xcode/DerivedData/YourProject-abc123/Index/DataStore. For Xcode 14 and later, the Index directory can be found as Index.noindex, which suppresses Spotlight indexing.

SwiftPM

By default, Periphery looks for the index store at .build/debug/index/store. Therefore, if you intend to run Periphery directly after calling swift test, you can omit the --index-store-path option, and Periphery will use the index store created when the project was built for testing. However if this isn't the case, then you must provide Periphery the location of the index store with --index-store-path.

Build Systems

Periphery can analyze projects using third-party build systems such as Bazel, though it cannot drive them automatically like SwiftPM and xcodebuild. Instead, you need to specify the index store location and provide a file-target mapping file.

A file-target mapping file contains a simple mapping of source files to build targets. You will need to generate this file yourself using the appropriate tooling for your build system. The format is as follows:

{
  "file_targets": {
    "path/to/file_a.swift": ["TargetA"],
    "path/to/file_b.swift": ["TargetB", "TargetC"]
  }
}

Tip

Relative paths are assumed to be relative to the current directory.

You can then invoke periphery as follows:

periphery scan --file-targets-path map.json --index-store-path index/store

Tip

Both options support multiple paths.

Platforms

Periphery supports both macOS and Linux. macOS supports both Xcode and Swift Package Manager (SPM) projects, whereas only SPM projects are supported on Linux.

Troubleshooting

Erroneous results in one or more files, such as false-positives and incorrect source file locations

It's possible for the index store to become corrupt, or out of sync with the source file. This can happen, for example, if you forcefully terminate (^C) a scan. To rectify this, you can pass the --clean-build flag to the scan command to force removal of existing build artifacts.

Code referenced within preprocessor macro conditional branch is unused

When Periphery builds your project it uses the default build configuration, which is typically 'debug'. If you use preprocessor macros to conditionally compile code, Periphery will only have visibility into the branches that are compiled. In the example below, releaseName will be reported as unused as it is only referenced within the non-debug branch of the macro.

struct BuildInfo {
    let debugName = "debug"
    let releaseName = "release" // 'releaseName' is unused

    var name: String {
        #if DEBUG
        debugName
        #else
        releaseName
        #endif
    }
}

You've a few options to workaround this:

  • Use Comment Commands to explicitly ignore releaseName.
  • Filter the results to remove known instances.
  • Run Periphery once for each build configuration and merge the results. You can pass arguments to the underlying build by specifying them after --, e.g periphery scan ... -- -configuration release.

Swift package is platform-specific

Periphery uses swift build to compile a Swift package which will fail if the Swift package is platform-specific (e.g. to iOS).

As a workaround, you can manually build the Swift package with xcodebuild and then use the --skip-build and --index-store-path options to target the index store previously produced by xcodebuild.

Example:

# 1. use xcodebuild
xcodebuild -scheme MyScheme -destination 'platform=iOS Simulator,OS=16.2,name=iPhone 14' -derivedDataPath '../dd' clean build

# 2. use produced index store for scanning
periphery scan --skip-build --index-store-path '../dd/Index.noindex/DataStore/'

Known Bugs

Due to some underlying bugs in Swift, Periphery may in some instances report incorrect results.

ID Title
56559 Index store does not relate constructor referenced via Self
56541 Index store does not relate static property getter used as subscript key
56327 Index store does not relate objc optional protocol method implemented in subclass
56189 Index store should relate appendInterpolation from string literals
56165 Index store does not relate constructor via literal notation
49641 Index does not include reference to constructor of class/struct with generic types

Sponsors Sponsors

Periphery is passion project that takes a huge amount of effort to maintain and develop. If you find Periphery useful, please consider sponsoring through GitHub Sponsors.

Special thanks goes to the following generous sponsors:

Emerge Tools

Emerge Tools is a suite of revolutionary products designed to supercharge mobile apps and the teams that build them.

periphery's People

Contributors

a2 avatar almazrafi avatar amseddi avatar bricker avatar cameroncooke avatar dazy1030 avatar dependabot[bot] avatar flashspys avatar fromatom avatar garry-jeromson avatar geraldwilliam avatar gettoset avatar hisaac avatar ileitch avatar iron-ham avatar jeehut avatar joshuatbrown avatar kateinoigakukun avatar leberwurstsaft avatar liamnichols avatar manicmaniac avatar marcelofabri avatar marcoeidinger avatar mike-at-home avatar mildm8nnered avatar ranunez avatar rock88 avatar rofle100lvl avatar rogerluan avatar schlabbi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

periphery's Issues

Need help to use XCode 11 branch

I've installed periphery via homebrew, and its usage is pretty straightforward, just open the terminal and execute periphery scan. But due to the XCode 11 issues, I can't do that.

So, I'm trying to use the XCode 11 branch, to see if I can work with that, but I don't even know how to start. Quoting from this thread:

If I run PeripheryKit or Periphery-Package scheme, nothing seems to happen, and if I run periphery scheme, it crashes with:

dyld: Library not loaded: @rpath/lib_InternalSwiftSyntaxParser.dylib
Reason: image not found

So yeah, I'm still clueless ^^''
Should I open another thread to avoid going offtopic here?

My question is: How exactly can I use the XCode 11 branch to scan my project?

Directory including whitespace cannot used in SourceKit

Note: After removing whitespace from directory, below error has resolved.

Error: SourceKit index request failed for file '/Users/d_date/dev/***/App/Screens/Item Detail/ItemDetailState.swift': '/Users/d_date/dev/***/App/Screens/Item Detail/ItemDetailState.swift' is not part of the input files.

Xcode Build target fails on "error shell command - exit code '65' "

@ileitch The periphery scan is working via the terminal. However after creating a xcode integration by adding a new target it does work.
I have used the same script that has been populated while running on the terminal.
The run script is as follows:
periphery scan --workspace example.xcworkspace --schemes example --targets example --format xcode --no-retain-public --verbose

The error am getting is as follows:

error: Shell command 'xcodebuild -workspace example.xcworkspace -scheme example -parallelizeTargets -derivedDataPath /Users/domainName/Library/Caches/com.peripheryapp.periphery/DerivedData-0176171cd3316b9abbf823f16dc75ce945d4a250 build CODE_SIGNING_ALLOWED="NO" ENABLE_BITCODE="NO" SWIFT_COMPILATION_MODE="wholemodule" DEBUG_INFORMATION_FORMAT="dwarf"' returned exit status '65':
User defaults from command line:
    IDEDerivedDataPathOverride = /Users/domainName/Library/Caches/com.peripheryapp.periphery/DerivedData-0176171cd3316b9abbf823f16dc75ce945d4a250

Build settings from command line:
    CODE_SIGNING_ALLOWED = "NO"
    DEBUG_INFORMATION_FORMAT = "dwarf"
    ENABLE_BITCODE = "NO"
    SWIFT_COMPILATION_MODE = "wholemodule"
    TOOLCHAINS = com.apple.dt.toolchain.XcodeDefault

Periphery does not run on macOS Catalina

New security and sandboxing features on macOS Catalina prevent periphery from running on the system. The app must be updated with conformance to the new security protocols in order to be allowed to run.

Error running scan - connection interrupted

Whilst running the scan command as follows:

periphery scan  --workspace "/Users/myUser/Documents/pathToWorkspace/MyWorkspace.xcworkspace/" --schemes "MyScheme"  --targets "MyTarget"  --no-retain-public

I encountered a connection interrupted error and was unable to proceed, here's the output:

sourcekit: [1:connection-event-handler:20523: 0.0000] Connection interruptsourcekit: [1:updateSemanticEditorDelay:20523: 0.0015] disabling semantic editor for 10 secondssourcekit: [1:pingService:20523: 0.0016] pinging servicesourcekit: [1:ping-event-handler:20523: 0.0107] service restorederror: SourceKit cursorInfo request failed for file '/Users/myUser/Documents/projects/pathToViewController/MyViewController.swift': Connection interrupted
* Inspecting project configuration...
* Building MyScheme...
* Indexing...
Command PhaseScriptExecution failed with a nonzero exit code

It looks as though this is more a bug with SourceKit than with Periphery but thought it might be worth asking whether or not this is a known issue? Thanks in advance.

False positive for instance-comparing control flow

Example code:

class MyClass {
    var myVar: AnotherClass?

    func callback(_ sender: AnotherClass?) {
        if sender === myVar {
            doOnMatch()
        } else {
            doOnMismatch()
        }
    }

    func doOnMatch() {} // reported as unused
    func doOnMismatch() {} // reported as unused
}

Error inspecting Siri Message Intent

I'm receiving the following error with my project that has a Siri Message Intent extension:
error: dataCorrupted(Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "productType", intValue: nil)], debugDescription: "Cannot initialize PBXProductType from invalid String value com.apple.product-type.app-extension.intents-service", underlyingError: nil)).

Is this extension type not currently supported?

Make periphery return non-zero exit code on warnings

I'd like to configure Periphery on our CI and configured everything like this (see our template project):

project: NewProjectTemplate.xcodeproj
schemes: [App]
targets: [App, Tests, UITests]
report_exclude:
  - App/Generated/SwiftGen/*.swift
  - App/SupportingFiles/*.swift
retain_public: false
quiet: true

But when I run periphery scan on the CI the builds always succeed even when I willingly add some unused code to test if the CI is failing. This is due to there being no option to make periphery return with a non-zero exit code for warnings (I don't know if it even returns with 0 on errors) โ€“ but for our purpose it would be grate to have an option like fail_on_warnings or -f or -w when calling the executable so this works.

File "is not part of the input files".

I wonder why some file might not be a part of input files?
Each scan random file causes an error.
Output provided:

โžœ  Prjct git:(refactoring/unused) peripheryscan 
[shell] xcodebuild -version
Xcode 10.2.1
Build version 10E1001
[version] 1.5.1
[configuration]
--- # .periphery.yml
aggressive: false
diagnose: false
disable_update_check: false
format: xcode
index_exclude: []
project: null
quiet: false
report_exclude: []
retain_objc_annotated: true
retain_public: false
retain_unused_protocol_func_params: false
save_build_log: null
schemes:
- Prjct Dev
strict: false
targets:
- Prjct Dev
use_build_log: null
verbose: true
workspace: /Users/julia/Documents/Prjct/Prjct.xcworkspace/

* Inspecting project configuration...
[workspace] Loading /Users/julia/Documents/Prjct/Prjct.xcworkspace/...
[project] Loading /Users/julia/Documents/Prjct/Prjct.xcodeproj...
[project] Loading /Users/julia/Documents/Prjct/Pods/Pods.xcodeproj...
[shell] xcodebuild -workspace /Users/julia/Documents/Prjct/Prjct.xcworkspace -list -json
[shell] xcodebuild -project /Users/julia/Documents/Prjct/Prjct.xcodeproj -showBuildSettings -target Prjct Dev -configuration Debug -xcconfig /Users/julia/Documents/Prjct/Pods/Target Support Files/Pods-Prjct Dev/Pods-Prjct Dev.debug.xcconfig build
[shell] rm -rf /Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6
[shell] xcodebuild -workspace /Users/julia/Documents/Prjct/Prjct.xcworkspace -showBuildSettings -scheme Prjct Dev build test
* Building Prjct Dev...
[shell] xcodebuild -workspace /Users/julia/Documents/Prjct/Prjct.xcworkspace -scheme Prjct Dev -parallelizeTargets -derivedDataPath /Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6 build CODE_SIGNING_ALLOWED="NO" ENABLE_BITCODE="NO" SWIFT_COMPILATION_MODE="wholemodule" DEBUG_INFORMATION_FORMAT="dwarf"
* Indexing...
[arguments:'Prjct Dev'] ["-incremental", "-module-name", "PrjctApp", "-Onone", "-enable-batch-mode", "-enforce-exclusivity=checked", "-DDEBUG", "-D", "COCOAPODS", "-D", "PRJCTONESIGNAL", "-D", "PRJCTMINDBOX", "-Xcc", "-fmodule-map-file=/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Products/Debug-iphoneos/PrjctMindbox/PrjctMindbox.modulemap", "-Xcc", "-fmodule-map-file=/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Products/Debug-iphoneos/PrjctOOM/PrjctOOM.modulemap", "-sdk", "/Applications/Xcode_10_2_1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk", "-target", "armv7-apple-ios10.0", "-g", "-module-cache-path", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/ModuleCache.noindex", "-Xfrontend", "-serialize-debugging-options", "-application-extension", "-enable-testing", "-index-store-path", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Index/DataStore", "-swift-version", "5", "-Xlinker", "-rpath", "-Xlinker", "/usr/lib/swift", "-I", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Products/Debug-iphoneos", "-I", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Products/Debug-iphoneos/PrjctMindbox", "-I", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Products/Debug-iphoneos/PrjctOOM", "-F", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Products/Debug-iphoneos", "-F", "/Users/julia/Documents/Prjct/Pods/OneSignal/iOS_SDK/OneSignalSDK/Framework", "-c", "-j4", "-output-file-map", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct Dev Notifications.build/Objects-normal/armv7/Prjct Dev Notifications-OutputFileMap.json", "-parseable-output", "-serialize-diagnostics", "-emit-dependencies", "-emit-module", "-emit-module-path", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct Dev Notifications.build/Objects-normal/armv7/PrjctApp.swiftmodule", "-Xcc", "-I/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct\\ Dev\\ Notifications.build/swift-overrides.hmap", "-Xcc", "-iquote", "-Xcc", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct Dev Notifications.build/Prjct Dev Notifications-generated-files.hmap", "-Xcc", "-I/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct\\ Dev\\ Notifications.build/Prjct\\ Dev\\ Notifications-own-target-headers.hmap", "-Xcc", "-I/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct\\ Dev\\ Notifications.build/Prjct\\ Dev\\ Notifications-all-non-framework-target-headers.hmap", "-Xcc", "-ivfsoverlay", "-Xcc", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/all-product-headers.yaml", "-Xcc", "-iquote", "-Xcc", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct Dev Notifications.build/Prjct Dev Notifications-project-headers.hmap", "-Xcc", "-I/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Products/Debug-iphoneos/include", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/PrjctCommon", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/Amplitude-iOS", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/Branch", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/FBSDKCoreKit", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/FBSDKLoginKit", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/FLAnimatedImage", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/Firebase", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/FirebaseAnalyticsInterop", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/FirebaseCore", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/FirebaseInstanceID", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/FirebaseMessaging", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/GTMSessionFetcher", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/GoogleToolboxForMac", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/GoogleUtilities", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/HMSegmentedControl", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/Protobuf", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/RxCocoa", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/SDWebImage", "-Xcc", "-I/Users/julia/Documents/Prjct/Pods/Headers/Public/nanopb", "-Xcc", "-I/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct\\ Dev\\ Notifications.build/DerivedSources-normal/armv7", "-Xcc", "-I/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct\\ Dev\\ Notifications.build/DerivedSources/armv7", "-Xcc", "-I/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct\\ Dev\\ Notifications.build/DerivedSources", "-Xcc", "-DDEBUG=1", "-Xcc", "-DCOCOAPODS=1", "-emit-objc-header", "-emit-objc-header-path", "/Users/julia/Library/Caches/com.peripheryapp.periphery/DerivedData-cad662947d99f378551be5a861fd12bde77711a6/Build/Intermediates.noindex/Prjct.build/Debug-iphoneos/Prjct Dev Notifications.build/Objects-normal/armv7/PrjctApp-Swift.h", "-working-directory", "/Users/julia/Documents/Prjct", "/Users/julia/Documents/Prjct/Prjct Notifications/EntryPointOneSignal.swift", "/Users/julia/Documents/Prjct/Prjct Notifications/EntryPointFallback.swift", "/Users/julia/Documents/Prjct/Prjct Notifications/EntryPointRepresentable.swift", "/Users/julia/Documents/Prjct/Prjct Notifications/EntryPoint.swift", "/Users/julia/Documents/Prjct/Prjct Notifications/EntryPointWrapper.swift", "/Users/julia/Documents/Prjct/Prjct Notifications/EntryPointMindbox.swift"]
error: SourceKit index request failed for file '/Users/julia/Documents/Prjct/Prjct/Deprecated/Entities/Order/ApiListOrderPayment.swift': '/Users/julia/Documents/Prjct/Prjct/Deprecated/Entities/Order/ApiListOrderPayment.swift' is not part of the input files
โžœ  Prjct git:(refactoring/unused) 

False positive function call on optional

Great tool! However, I am finding some issues with functions called from optionals...

if let container: DetailContainerView = parent as? DetailContainerView {
container.updateToolbar(enable: enable)
}

updateToolbar(enable: Bool) function on DetailContainerView is marked as unused.

Xcode 11 support

I got error: unknownTokenKind("ellipsis"). I believe it is Xcode 11 issue, because 10.3 works fine. And I'm not alone: #39 (comment)

It would be great to have Xcode 11 support? Thanks

Xcode integration

Thanks a lot for open sourcing periphery !
Do you think that it is possible to integrate scan results into Xcode as warnings (like Swiftlint does) ?
Or even better as an Xcode plugin ? (not likely IMHO)
Is this something that we can help with ?

Projects not found within a workspace if placed within a folder group

Projects are not found within a workspace if they're inside a container group backed by a folder.

.xcworkspace

  • Parent Project: Periphery Bug Report.xcodeproj
  • Group: Modules
    • Nested Project: Nested Framework Module.xcodeproj

Steps to reproduce

  1. Download periphery-bug-nested-projects.zip
  2. Unarchive ZIP file
  3. Run periphery scan within the uncompressed same folder (containing Periphery Bug Report.xcworkspace)

Expected result

periphery to pick up all targets across both projects:

  • Periphery Bug Report/Periphery Bug Report.xcodeproj
  • Modules/Nested Framework Module/Nested Framework Module.xcodeproj

Actual result

periphery fails with an error, not finding Nested Framework Module.xcodeproj.

warning: No such project exists at '/periphery-bug-nested-projects/Nested Framework Module/Nested Framework Module.xcodeproj', referenced by /periphery-bug-nested-projects/Periphery Bug Report.xcworkspace/'.

The path is incorrect, missing the Modules group container location as part of the full path to the project. Instead it should look as follows:

- /periphery-bug-nested-projects/Nested Framework Module/Nested Framework Module.xcodeproj
+ /periphery-bug-nested-projects/Modules/Nested Framework Module/Nested Framework Module.xcodeproj

How to rename methods and variables

I know it's A tool to identify unused code in Swift projects.

But I want to know if there is a way to rename methods and variables.
Includes renaming of references.

Exclude methods

Is it possible to exclude methods or maybe methods that implement a protocol?
Example:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

Most of the time view controller has only one table, so it actually doesn't need the tableView parameter.
Or is there any other solution to get rid of such warnings?

SPM support

error: The element XCSwiftPackageProductDependency is not supported.
* Inspecting project configuration...

Xcode 11.0

Error while running `periphery scan`

Error message: Failed to determine build arguments for target 'TargetName' with module name 'TargetName'

Can you please tell what am I missing here?

False positives for Protocol type aliases

typealias PersistenceProtocol = ThreadPersistenceProtocol & MessagePersistenceProtocol

struct Persistence: PersistenceProtocol {
 (...)
}

The Persistence struct is being used everywhere but I am still getting warnings for PersistenceProtocol, ThreadPersistenceProtocol, MessagePersistenceProtocol being unused

wrong handling of project path with blank

Please take a look at the following Terminal output:

jakob@mkwnh Pix % periphery version 
1.6.0
jakob@mkwnh Pix % periphery scan
Welcome to Periphery!
This guided setup will help you select the appropriate configuration for your project.

* Inspecting project configuration...

Select build targets to analyze:
? Delimit choices with a single space, e.g: 1 2 3
1 Pix
> 1

Select the schemes necessary to build your chosen targets:
? Delimit choices with a single space, e.g: 1 2 3
1 AppUtilLib
2 Pix
> 2

Assume all 'public' declarations are in use?
? You should choose Y here if your public interfaces are not used by any selected build target, such as may be the case for a framework project.
(Y)es/(N)o > N

* Executing command:
periphery scan \
  --project "/Users/jakob/Library/Mobile Documents/com~apple~CloudDocs/backed-up/Development/Pix/Pix.xcodeproj/" \
  --schemes "Pix" \
  --targets "Pix" \
  --no-retain-public

* Inspecting project configuration...
* Building Pix...
error: Shell command '/bin/sh -c xcodebuild -project /Users/jakob/Library/Mobile Documents/com~apple~CloudDocs/backed-up/Development/Pix/Pix.xcodeproj -scheme Pix -parallelizeTargets -derivedDataPath '/Users/jakob/Library/Caches/com.peripheryapp.periphery/DerivedData-e8c9438f854bfc3851d7b4b90c034b9261dcd50e' build CODE_SIGNING_ALLOWED="NO" ENABLE_BITCODE="NO" SWIFT_COMPILATION_MODE="wholemodule" DEBUG_INFORMATION_FORMAT="dwarf"' returned exit status '65':
Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -project /Users/jakob/Library/Mobile "Documents/com~apple~CloudDocs/backed-up/Development/Pix/Pix.xcodeproj" -scheme Pix -parallelizeTargets -derivedDataPath /Users/jakob/Library/Caches/com.peripheryapp.periphery/DerivedData-e8c9438f854bfc3851d7b4b90c034b9261dcd50e build

User defaults from command line:
    IDEDerivedDataPathOverride = /Users/jakob/Library/Caches/com.peripheryapp.periphery/DerivedData-e8c9438f854bfc3851d7b4b90c034b9261dcd50e

xcodebuild: error: Unknown build action 'Documents/com~apple~CloudDocs/backed-up/Development/Pix/Pix.xcodeproj'.

It looks pretty much as if the blank (' ') in the name of the folder "Mobile Documents" (which I cannot change) causes the error. Maybe the whole path "/Users/jakob/Library/Mobile Documents/com~apple~CloudDocs/backed-up/Development/Pix/Pix.xcodeproj" should be put between quote signs in the shell command.

Cannot parse scheme containing whitespace

It seems that the name of the scheme passed to xcodeproj needs to be double-quoted.

[shell] xcodebuild -version
Xcode 11.4
Build version 11E146
[version] 1.6.0
[configuration]
--- # .periphery.yml
aggressive: false
diagnose: false
disable_update_check: false
format: xcode
index_exclude: []
project: Cafe.xcodeproj
quiet: false
report_exclude: []
retain_objc_annotated: true
retain_public: true
retain_unused_protocol_func_params: true
save_build_log: null
schemes:
- App Staging
strict: false
targets:
- App
- ComposableArchitecture
- Shared
use_build_log: null
verbose: true
workspace: null
xcargs: null

* Inspecting project configuration...
[project] Loading Cafe.xcodeproj...
[shell] xcodebuild -project /Users/d_date/dev/***/***.xcodeproj -list -json
[shell] xcodebuild -project /Users/d_date/dev/***/***.xcodeproj -showBuildSettings -target App -configuration Develop Debug build
[shell] xcodebuild -project /Users/d_date/dev/***/***.xcodeproj -showBuildSettings -target Shared -configuration Develop Debug build
[shell] xcodebuild -project /Users/d_date/dev/***/***.xcodeproj -showBuildSettings -target ComposableArchitecture -configuration Develop Debug build
[shell] rm -rf /Users/d_date/Library/Caches/com.peripheryapp.periphery/DerivedData-37efa8a9905492fa64937d5854b015e8e0d800be
[shell] xcodebuild -project /Users/d_date/dev/***/***.xcodeproj -showBuildSettings -scheme App Staging build test
* Building App Staging...
[shell] /bin/sh -c xcodebuild -project /Users/d_date/dev/***/***.xcodeproj -scheme App Staging -parallelizeTargets -derivedDataPath '/Users/d_date/Library/Caches/com.peripheryapp.periphery/DerivedData-37efa8a9905492fa64937d5854b015e8e0d800be' build CODE_SIGNING_ALLOWED="NO" ENABLE_BITCODE="NO" SWIFT_COMPILATION_MODE="wholemodule" DEBUG_INFORMATION_FORMAT="dwarf"
Error: Shell command '/bin/sh -c xcodebuild -project /Users/d_date/dev/***/***.xcodeproj -scheme App Staging -parallelizeTargets -derivedDataPath '/Users/d_date/Library/Caches/com.peripheryapp.periphery/DerivedData-37efa8a9905492fa64937d5854b015e8e0d800be' build CODE_SIGNING_ALLOWED="NO" ENABLE_BITCODE="NO" SWIFT_COMPILATION_MODE="wholemodule" DEBUG_INFORMATION_FORMAT="dwarf"' returned exit status '65':
Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -project /Users/d_date/dev/***/***.xcodeproj -scheme App Staging -parallelizeTargets -derivedDataPath /Users/d_date/Library/Caches/com.peripheryapp.periphery/DerivedData-37efa8a9905492fa64937d5854b015e8e0d800be build

User defaults from command line:
    IDEDerivedDataPathOverride = /Users/d_date/Library/Caches/com.peripheryapp.periphery/DerivedData-37efa8a9905492fa64937d5854b015e8e0d800be

xcodebuild: error: Unknown build action 'Staging'.

False positive on static protocol variables

It's hard to say what exactly triggers the warning in the example below. There is a static generic function on a protocol extension checking for a type and based on the type return an instance of UIViewController either from XIB or Storyboard.

The result stays the same if I have those XIB and Storyboard defined, of course. When I execute this code in my example project it prints descriptions of all 3 views, which proves they were loaded.

protocol P1 {
    static func instantiate<T: UIViewController>() -> T where T: P1
    static var identifier: String { get }  //// Warning here
}

protocol P2: P1 {
    static var storyboard: String { get }  //// Warning here
}

extension P1 {
    static var identifier: String {    //// Warning here
        return String(describing: self)
    }
}

extension P1 {
    static func instantiate<T: UIViewController>() -> T where T: P1 {
        guard let storyboard = (T.self as? P2.Type)?.storyboard else {
            return T(nibName: T.identifier, bundle: nil)
        }
        guard let result = UIStoryboard(name: storyboard, bundle: nil).instantiateViewController(withIdentifier: T.identifier) as? T  else {
            fatalError("No expected controller found")
        }
        return result
    }
}

class C1: UIViewController, P1 {
}

class C2: UIViewController, P2 {
    static var storyboard: String { return "Main" }  //// Warning here
}

class C3: UIViewController, P2 {
    static var storyboard: String { return "Main" }  //// Warning here
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let c1: C1 = C1.instantiate()

        let c2: C2 = C2.instantiate()

        let c3: C3 = C3.instantiate()

        print(c1.view)
        print(c2.view)
        print(c3.view)
    }

}

Indexing always fails with Xcode 10.2 beta

Hello,

If I point xcode-select to Xcode 10.2 beta 2, periphery scan indexing phase fails with error:

error: SourceKit editorOpen request failed for file '/Users/myUser/longPath/MyClass.swift': Retrieving both the document structure and a syntax tree at the same time is not supported. Use the syntax tree to compute the document structure.

You can find the message in SwiftEditor sources.

Please fix.

Seeing several false positives (I think)

Using periphery to analyze an open-source DI project. Part of it is a command-line MacOS tool. You can get the source here : https://github.com/uber/needle/tree/master/Generator

In that Generator directory, please run swift package generate-xcodeproj --xcconfig-overrides xcode.xcconfig to create an Xcode project.

Once that's done we can run ../Periphery scan --project /Users/rudro/workspace/needle/Generator/Needle.xcodeproj --schemes needle --targets NeedleFramework (the capital letter due to me using a local build of periphery).

Some of the warnings are great.

e.g:
/Users/rudro/workspace/needle/Generator/Sources/NeedleFramework/Generating/DependencyProviderContentTask.swift:22:8: warning: Struct 'PropertyNotFoundErrorInfo' is unused
This is indeed an unused struct.

However, there are many problematic warnings. Let's start with just one:
/Users/rudro/workspace/needle/Generator/Sources/NeedleFramework/Generating/DependencyProviderContentTask.swift:37:5: warning: Initializer 'init(providers:)' is unused

It warns that this init is not used: https://github.com/uber/needle/blob/4ca57ee2bd0c34022c2de2cb0fcbd2a9cb93eb17/Generator/Sources/NeedleFramework/Generating/DependencyProviderContentTask.swift#L37

However, it's used here : https://github.com/uber/needle/blob/4ca57ee2bd0c34022c2de2cb0fcbd2a9cb93eb17/Generator/Sources/NeedleFramework/Generating/DependencyGraphExporter.swift#L79

Could you have a look and let me know if I am missing some command-line params ? Once I get a response, I'll move down the list to the other issues.

Thanks!

p.s. you can open the project in Xcode to verify that both files are part of the NeedleFoundation target.

Integration with Jenkins CI

Hello, as I am building full stack solution for keeping high code quality standards of my swift apps and I found your project which I find suitable for my Jenkins CI appliance.

I wanted to ask if it is possible to add XML formater for example in Checkstyle 4.3 XML format to easily integrate with jenkinsci/warnings-ng-plugin.

CocoaPods support

Would it be possible for you to add CocoaPods support?
By introducing with CocoaPods, we want to match the version of periphery within our development team.

Xcode 10.2.1 index request failure

Xcode 10.2.1
macOS 10.14.4
periphery 1.5.1

error: SourceKit index request failed for file [redacted]: [redacted] is not part of the input files

The error consistently presents on the same file. Please let me know if there's more information I can provide

Could not found extension declaration

public enum Alignment : Int {

case center

case left

case right

case fill

@available(iOS 11.0, *)
case leading

@available(iOS 11.0, *)
case trailing

}

extension Alignment {// This could not found in ScanResult
func action() {
print(self.rawValue)
}

static func staticAction() {
    print(Alignment.self)
}

}

It effects the Protocol, Enum, Struct etc...

๐Ÿ›‘ The Status of Periphery

Hey all, first off I'd like to apologize for not being responsive. To be fair to you all, it's time that I explain the status of Periphery and why I haven't been actively involved.

In Xcode 10.2 Apple introduced some large changes to source indexing, which unfortunately also introduced some bugs in the index output from SourceKit. I reported these issues to Apple and attempted to workaround them as best I could.

In Xcode 11 there were more indexing changes that again changed the format of the index output from SourceKit. It became very difficult to workaround these issues and get Periphery's test suite passing again. Frustrated with the situation, I reached out to some Apple engineers on twitter: https://twitter.com/peripheryappcom/status/1196059657183354880

The tl;dr is that Apple no longer supports the indexing output from SourceKit, since Xcode itself no longer uses it. They're ensuring that existing tests don't break, however I can only imagine their test coverage is lacking in many areas.

The recommended approach is to use https://github.com/apple/indexstore-db. Unfortunately this would require a near complete re-write of Periphery. There's also no guarantee that all of Periphery's analysis techniques can be adapted to IndexStoreDB. I personally have no desire to undertake this work, though I'm more than happy to provide support & guidance for anyone that wishes to attempt this.

So there you have it. Unless someone steps up to continue developing Periphery, I'm afraid it's pretty much dead.

The element XCSwiftPackageProductDependency is not supported.

When I try to run periphery on my Xcode 11.3 Swift project, it aborts quickly with this error message.

jakob@mkwnh Pix % periphery scan
Welcome to Periphery!
This guided setup will help you select the appropriate configuration for your project.

* Inspecting project configuration...

error: The element XCSwiftPackageProductDependency is not supported.

Indexing always fails with Xcode 10.2

From #8:

+1 with @Sam-Spencer

I've just compiled the xcode10.2 branch, and Periphery failed with the following error:

* Inspecting project configuration...
* Building Acrostics...
* Indexing...
objc[30286]: __SwiftNativeNSError object 0x7f85eb111ab0 overreleased while already deallocating; break on objc_overrelease_during_dealloc_error to debug
error: SourceKit editorOpen request failed for file '[REDACTED]': Retrieving both the document structure and a syntax tree at the same time is not supported. Use the syntax tree to compute the document structure.

This is still broken.

Initializers declared as extension on Array are reported as unused

Original issue: https://github.com/peripheryapp/issues/issues/3 by ateliercw

Given a simplified example of:

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = [String](title: "Title").first
    }
}

extension Array where Element == String {
    init(title: String) {
        self = [title]
    }
}

Periphery will report:

PeripheryTest/PeripheryTest/ViewController.swift:11:5: warning: Initializer 'init(title:)' is unused

This is causing a lot of false positives in a larger project that I'm working on do to expensive use of typed extensions on Array providing custom initializers.

SourceKit error

When I try to scan my project, here is the error I'm always getting:

SourceKit editorOpen request failed for file '/Users/arguiot/GitHub/StudIO/StudIO/Extensions/Compression.swift': Retrieving both the document structure and a syntax tree at the same time is not supported. Use the syntax tree to compute the document structure.

UIViewController sub-subclasses false hit for required init

Xcode 10.1, anywhere in the project that I am using a class like this UIViewController > MySubViewController > MySubSubViewController - implementation of required init?(coder aDecoder: NSCoder) is falsely flagged as unused in MySubSubViewController.

It also appears that any methods called exclusively from within those inits are also falsely flagged.

Run script contains --format xcode --no-retain-objc-annotated

Error Inspecting Project Configuration

error: typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "defaultConfigurationIsVisible", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))

I'll try building from source to see what's going on.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.