Skip to content

Commit

Permalink
Automatic target detection (#767)
Browse files Browse the repository at this point in the history
  • Loading branch information
ileitch committed Aug 10, 2024
1 parent a4b6cf1 commit 0758d1e
Show file tree
Hide file tree
Showing 222 changed files with 807 additions and 1,224 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,4 @@ jobs:
- name: Test
run: ${{ env.swift_test }}
- name: Scan
run: ${{ env.periphery_scan }} --config .periphery.linux.yml
run: ${{ env.periphery_scan }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ DerivedData
*.gcda
*.gcno
.swiftpm
Tests/Fixtures/.build/

# VSCode
.vscode/*
11 changes: 0 additions & 11 deletions .periphery.linux.yml

This file was deleted.

13 changes: 0 additions & 13 deletions .periphery.yml

This file was deleted.

20 changes: 10 additions & 10 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser",
"state" : {
"revision" : "0fbc8848e389af3bb55c182bc19ca9d5dc2f255b",
"version" : "1.4.0"
"revision" : "41982a3656a71c768319979febd796c6fd111d5c",
"version" : "1.5.0"
}
},
{
Expand All @@ -59,35 +59,35 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax",
"state" : {
"revision" : "303e5c5c36d6a558407d364878df131c3546fad8",
"version" : "510.0.2"
"revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82",
"version" : "510.0.3"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system",
"state" : {
"revision" : "6a9e38e7bd22a3b8ba80bddf395623cf68f57807",
"version" : "1.3.1"
"revision" : "d2ba781702a1d8285419c15ee62fd734a9437ff5",
"version" : "1.3.2"
}
},
{
"identity" : "xcodeproj",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tuist/xcodeproj",
"state" : {
"revision" : "20d5803c70e4ac5d67151ea6f5624a8136ab8fe0",
"version" : "8.21.0"
"revision" : "7713589d4d1bceedd02899d9c44b8e57be05ea35",
"version" : "8.22.0"
}
},
{
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams",
"state" : {
"revision" : "9234124cff5e22e178988c18d8b95a8ae8007f76",
"version" : "5.1.2"
"revision" : "3036ba9d69cf1fd04d433527bc339dc0dc75433d",
"version" : "5.1.3"
}
}
],
Expand Down
49 changes: 2 additions & 47 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var dependencies: [Package.Dependency] = [
.package(url: "https://github.com/tadija/AEXML", from: "4.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"),
.package(url: "https://github.com/ileitch/swift-indexstore", from: "9.0.4"),
.package(url: "https://github.com/apple/swift-syntax", from: "510.0.2"),
.package(url: "https://github.com/apple/swift-syntax", from: "510.0.3"),
.package(url: "https://github.com/ileitch/swift-filename-matcher", from: "0.0.0")
]

Expand Down Expand Up @@ -64,7 +64,7 @@ var targets: [PackageDescription.Target] = [
dependencies: [
.target(name: "SourceGraph"),
.target(name: "Shared"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax")
]
),
.target(
Expand All @@ -89,43 +89,6 @@ var targets: [PackageDescription.Target] = [
],
path: "Tests/Shared"
),
.target(
name: "ExternalModuleFixtures",
path: "Tests/Fixtures/ExternalModuleFixtures"
),
.target(
name: "CrossModuleRetentionFixtures",
dependencies: [
.target(name: "CrossModuleRetentionSupportFixtures")
],
path: "Tests/Fixtures/CrossModuleRetentionFixtures"
),
.target(
name: "CrossModuleRetentionSupportFixtures",
path: "Tests/Fixtures/CrossModuleRetentionSupportFixtures"
),
.target(
name: "RetentionFixtures",
dependencies: [
.target(name: "ExternalModuleFixtures")
],
path: "Tests/Fixtures/RetentionFixtures"
),
.target(
name: "UnusedParameterFixtures",
path: "Tests/Fixtures/UnusedParameterFixtures",
swiftSettings: [
.unsafeFlags(["-suppress-warnings"]) // Suppress warnings from testLocalVariableAssignment
]
),
.target(
name: "TypeSyntaxInspectorFixtures",
path: "Tests/Fixtures/TypeSyntaxInspectorFixtures"
),
.target(
name: "DeclarationVisitorFixtures",
path: "Tests/Fixtures/DeclarationVisitorFixtures"
),
.testTarget(
name: "PeripheryTests",
dependencies: [
Expand Down Expand Up @@ -162,14 +125,6 @@ targets.append(contentsOf: [
.product(name: "XcodeProj", package: "XcodeProj")
]
),
.target(
name: "ObjcAccessibleRetentionFixtures",
path: "Tests/Fixtures/ObjcAccessibleRetentionFixtures"
),
.target(
name: "ObjcAnnotatedRetentionFixtures",
path: "Tests/Fixtures/ObjcAnnotatedRetentionFixtures"
),
.testTarget(
name: "XcodeTests",
dependencies: [
Expand Down
56 changes: 14 additions & 42 deletions Sources/Frontend/Commands/ScanBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,9 @@ final class ScanBehavior {
self.logger = logger
}

func setup(_ configPath: String?) -> Result<(), PeripheryError> {
func setup(_ configPath: FilePath?) -> Result<(), PeripheryError> {
do {
var path: FilePath?

if let configPath {
path = FilePath(configPath)
}
try configuration.load(from: path)
try configuration.load(from: configPath)
} catch let error as PeripheryError {
return .failure(error)
} catch {
Expand All @@ -31,27 +26,22 @@ final class ScanBehavior {

func main(_ block: (Project) throws -> [ScanResult]) -> Result<(), PeripheryError> {
logger.contextualized(with: "version").debug(PeripheryVersion)

let project: Project

if configuration.guidedSetup {
do {
do {
logger.debug(SwiftVersion.current.fullVersion)
try SwiftVersion.current.validateVersion()

if configuration.guidedSetup {
project = try GuidedSetup().perform()
} catch let error as PeripheryError {
return .failure(error)
} catch {
return .failure(.underlyingError(error))
}
} else {
project = Project.identify()

do {
// Guided setup performs validation itself once the type has been determined.
try project.validateEnvironment()
} catch let error as PeripheryError {
return .failure(error)
} catch {
return .failure(.underlyingError(error))
} else {
project = try Project.identify()
}
} catch let error as PeripheryError {
return .failure(error)
} catch {
return .failure(.underlyingError(error))
}

let updateChecker = UpdateChecker()
Expand Down Expand Up @@ -90,24 +80,6 @@ final class ScanBehavior {
logger.info(output, canQuiet: false)
logger.endInterval(interval)

if !filteredResults.isEmpty,
configuration.outputFormat.supportsAuxiliaryOutput {
logger.info(
colorize("\n* ", .boldGreen) +
colorize("Seeing false positives?", .bold) +

colorize("\n - ", .boldGreen) +
"Periphery only analyzes files that are members of the targets you specify." +
"\n References to declarations identified as unused may reside in files that are members of other targets, e.g test targets." +

colorize("\n - ", .boldGreen) +
"Periphery is a very precise tool, false positives often turn out to be correct after further investigation." +

colorize("\n - ", .boldGreen) +
"If it really is a false positive, please report it - https://github.com/peripheryapp/periphery/issues."
)
}

updateChecker.notifyIfAvailable()

if !filteredResults.isEmpty && configuration.strict {
Expand Down
36 changes: 18 additions & 18 deletions Sources/Frontend/Commands/ScanCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,24 @@ struct ScanCommand: FrontendCommand {
var setup: Bool = defaultConfiguration.guidedSetup

@Option(help: "Path to configuration file. By default Periphery will look for .periphery.yml in the current directory")
var config: String?
var config: FilePath?

@Option(help: "Path to your project's .xcworkspace. Xcode projects only")
var workspace: String?
@Option(help: "Path to your project's .xcodeproj or .xcworkspace")
var project: FilePath?

@Option(help: "Path to your project's .xcodeproj - supply this option if your project doesn't have an .xcworkspace. Xcode projects only")
var project: String?

@Option(parsing: .upToNextOption, help: "File target mapping configuration file paths. For use with third-party build systems")
var fileTargetsPath: [FilePath] = defaultConfiguration.$fileTargetsPath.defaultValue

@Option(parsing: .upToNextOption, help: "Schemes that must be built in order to produce the targets passed to the --targets option. Xcode projects only")
@Option(parsing: .upToNextOption, help: "Schemes to build. All targets built by these schemes will be scanned")
var schemes: [String] = defaultConfiguration.$schemes.defaultValue

@Option(parsing: .upToNextOption, help: "Target names to scan. Required for Xcode projects. Optional for Swift Package Manager projects, default behavior is to scan all targets defined in Package.swift")
var targets: [String] = defaultConfiguration.$targets.defaultValue

@Option(help: "Output format (allowed: \(OutputFormat.allValueStrings.joined(separator: ", ")))")
var format: OutputFormat = defaultConfiguration.$outputFormat.defaultValue

@Option(parsing: .upToNextOption, help: "Source file globs to exclude from indexing. Declarations and references within these files will not be considered during analysis")
@Flag(help: "Exclude test targets from indexing")
var excludeTests: Bool = defaultConfiguration.$excludeTests.defaultValue

@Option(parsing: .upToNextOption, help: "Targets to exclude from indexing")
var excludeTargets: [String] = defaultConfiguration.$excludeTargets.defaultValue

@Option(parsing: .upToNextOption, help: "Source file globs to exclude from indexing")
var indexExclude: [String] = defaultConfiguration.$indexExclude.defaultValue

@Option(parsing: .upToNextOption, help: "Source file globs to exclude from the results. Note that this option is purely cosmetic, these files will still be indexed")
Expand Down Expand Up @@ -118,14 +115,17 @@ struct ScanCommand: FrontendCommand {
var quiet: Bool = defaultConfiguration.$quiet.defaultValue

@Option(help: "JSON package manifest path (obtained using `swift package describe --type json` or manually)")
var jsonPackageManifestPath: String?
var jsonPackageManifestPath: FilePath?

@Option(help: "Baseline file path used to filter results")
var baseline: FilePath?

@Option(help: "Baseline file path where results are written. Pass the same path to '--baseline' in subsequent scans to exclude the results recorded in the baseline.")
var writeBaseline: FilePath?

@Option(help: "Project configuration for non-Apple build systems")
var genericProjectConfig: FilePath?

private static let defaultConfiguration = Configuration()

func run() throws {
Expand All @@ -137,11 +137,8 @@ struct ScanCommand: FrontendCommand {

let configuration = Configuration.shared
configuration.guidedSetup = setup
configuration.apply(\.$workspace, workspace)
configuration.apply(\.$project, project)
configuration.apply(\.$fileTargetsPath, fileTargetsPath)
configuration.apply(\.$schemes, schemes)
configuration.apply(\.$targets, targets)
configuration.apply(\.$indexExclude, indexExclude)
configuration.apply(\.$reportExclude, reportExclude)
configuration.apply(\.$reportInclude, reportInclude)
Expand All @@ -165,6 +162,8 @@ struct ScanCommand: FrontendCommand {
configuration.apply(\.$strict, strict)
configuration.apply(\.$indexStorePath, indexStorePath)
configuration.apply(\.$skipBuild, skipBuild)
configuration.apply(\.$excludeTests, excludeTests)
configuration.apply(\.$excludeTargets, excludeTargets)
configuration.apply(\.$skipSchemesValidation, skipSchemesValidation)
configuration.apply(\.$cleanBuild, cleanBuild)
configuration.apply(\.$buildArguments, buildArguments)
Expand All @@ -174,6 +173,7 @@ struct ScanCommand: FrontendCommand {
configuration.apply(\.$jsonPackageManifestPath, jsonPackageManifestPath)
configuration.apply(\.$baseline, baseline)
configuration.apply(\.$writeBaseline, writeBaseline)
configuration.apply(\.$genericProjectConfig, genericProjectConfig)

try scanBehavior.main { project in
try Scan().perform(project: project)
Expand Down
4 changes: 2 additions & 2 deletions Sources/Frontend/CommonSetupGuide.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import Shared

final class CommonSetupGuide: SetupGuideHelpers, SetupGuide {
final class CommonSetupGuide: SetupGuideHelpers {
private let configuration: Configuration

required init(configuration: Configuration = .shared) {
Expand All @@ -11,7 +11,7 @@ final class CommonSetupGuide: SetupGuideHelpers, SetupGuide {

func perform() throws {
print(colorize("\nAssume all 'public' declarations are in use?", .bold))
print(colorize("?", .boldYellow) + " You should choose 'Yes' here if your public interfaces are not used by any selected build target, as may be the case for a framework/library project.")
print(colorize("?", .boldYellow) + " Choose 'Yes' if your project is a framework/library without a main application target.")
configuration.retainPublic = selectBoolean()
}

Expand Down
Loading

0 comments on commit 0758d1e

Please sign in to comment.