Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ disabled_rules:
- non_optional_string_data_conversion # https://github.com/realm/SwiftLint/issues/5263#issuecomment-2115182747
- balanced_xctest_lifecycle
- todo
- for_where
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

- Unused parameter warnings are suppressed in `@available(*, unavailable)` functions.
- Fix handling of Xcode projects with single and double quotes in their path and scheme names.
- `@_dynamicReplacement` members are now retained.

## 3.0.3 (2025-03-15)

Expand Down
2 changes: 1 addition & 1 deletion Sources/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ swift_library(
"SourceGraph/Mutators/CodingKeyEnumReferenceBuilder.swift",
"SourceGraph/Mutators/ComplexPropertyAccessorReferenceBuilder.swift",
"SourceGraph/Mutators/DefaultConstructorReferenceBuilder.swift",
"SourceGraph/Mutators/DynamicMemberLookupReferenceBuilder.swift",
"SourceGraph/Mutators/DynamicMemberRetainer.swift",
"SourceGraph/Mutators/EntryPointAttributeRetainer.swift",
"SourceGraph/Mutators/EnumCaseReferenceBuilder.swift",
"SourceGraph/Mutators/ExtensionReferenceBuilder.swift",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Configuration
import Foundation
import Shared

final class DynamicMemberLookupReferenceBuilder: SourceGraphMutator {
final class DynamicMemberRetainer: SourceGraphMutator {
private let graph: SourceGraph

required init(graph: SourceGraph, configuration _: Configuration, swiftVersion _: SwiftVersion) {
Expand All @@ -15,5 +15,11 @@ final class DynamicMemberLookupReferenceBuilder: SourceGraphMutator {
graph.markRetained(decl)
}
}

for decl in graph.declarations(ofKinds: [.functionSubscript, .varInstance, .functionMethodInstance]) {
if decl.attributes.contains("_dynamicReplacement") {
graph.markRetained(decl)
}
}
}
}
2 changes: 1 addition & 1 deletion Sources/SourceGraph/SourceGraphMutatorRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public final class SourceGraphMutatorRunner {
ExternalTypeProtocolConformanceReferenceRemover.self,
ComplexPropertyAccessorReferenceBuilder.self,
EnumCaseReferenceBuilder.self,
DynamicMemberLookupReferenceBuilder.self,
DefaultConstructorReferenceBuilder.self,
StructImplicitInitializerReferenceBuilder.self,

DynamicMemberRetainer.self,
UnusedParameterRetainer.self,
AssetReferenceRetainer.self,
EntryPointAttributeRetainer.self,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
struct FixtureStruct8 {
dynamic static func originalStaticMethod() {}
dynamic func originalMethod() {}
dynamic var originalProperty: Int { 0 }
dynamic subscript(original index: Int) -> Int { 0}
}

extension FixtureStruct8 {
@_dynamicReplacement(for: originalMethod)
func replacementMethod() {}

@_dynamicReplacement(for: originalProperty)
var replacementProperty: Int { 0 }

@_dynamicReplacement(for: subscript(original:))
subscript(replacement index: Int) -> Int { 0}
}

public struct FixtureStruct8Retainer {
public func retain() {
let strct = FixtureStruct8()
strct.originalMethod()
_ = strct.originalProperty
_ = strct[original: 0]
}
}
83 changes: 49 additions & 34 deletions Tests/PeripheryTests/RetentionTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,55 @@ final class RetentionTest: FixtureSourceGraphTestCase {
}
}

func testMainActorAnnotation() {
analyze(retainPublic: true) {
assertReferenced(.class("FixtureClass132")) {
self.assertReferenced(.functionConstructor("init(value:)"))
}
assertReferenced(.class("FixtureClass133"))
}
}

// https://github.com/apple/swift/issues/64686
// https://github.com/peripheryapp/periphery/issues/264
func testSelfReferencedConstructor() {
analyze(retainPublic: true) {
assertReferenced(.struct("FixtureStruct3")) {
self.assertReferenced(.functionConstructor("init(value:)"))
}
assertReferenced(.struct("FixtureStruct4")) {
self.assertReferenced(.functionConstructor("init(value:)"))
}
assertReferenced(.struct("FixtureStruct5")) {
self.assertNotReferenced(.functionConstructor("init(value:)"))
}
}
}

// https://github.com/apple/swift/issues/56541
func testStaticMemberUsedAsSubscriptKey() {
analyze(retainPublic: true) {
assertReferenced(.enum("FixtureEnum128")) {
self.assertReferenced(.varStatic("someVar"))
}
}
}

func testRetainsDynamicReplacement() {
analyze(retainPublic: true) {
assertReferenced(.struct("FixtureStruct8")) {
self.assertReferenced(.functionMethodInstance("originalMethod()"))
self.assertReferenced(.functionMethodInstance("replacementMethod()"))

self.assertReferenced(.varInstance("originalProperty"))
self.assertReferenced(.varInstance("replacementProperty"))

self.assertReferenced(.functionSubscript("subscript(original:)"))
self.assertReferenced(.functionSubscript("subscript(replacement:)"))
}
}
}

// MARK: - Swift Testing

#if canImport(Testing)
Expand Down Expand Up @@ -1613,40 +1662,6 @@ final class RetentionTest: FixtureSourceGraphTestCase {
}
}

func testMainActorAnnotation() {
analyze(retainPublic: true) {
assertReferenced(.class("FixtureClass132")) {
self.assertReferenced(.functionConstructor("init(value:)"))
}
assertReferenced(.class("FixtureClass133"))
}
}

// https://github.com/apple/swift/issues/64686
// https://github.com/peripheryapp/periphery/issues/264
func testSelfReferencedConstructor() {
analyze(retainPublic: true) {
assertReferenced(.struct("FixtureStruct3")) {
self.assertReferenced(.functionConstructor("init(value:)"))
}
assertReferenced(.struct("FixtureStruct4")) {
self.assertReferenced(.functionConstructor("init(value:)"))
}
assertReferenced(.struct("FixtureStruct5")) {
self.assertNotReferenced(.functionConstructor("init(value:)"))
}
}
}

// https://github.com/apple/swift/issues/56541
func testStaticMemberUsedAsSubscriptKey() {
analyze(retainPublic: true) {
assertReferenced(.enum("FixtureEnum128")) {
self.assertReferenced(.varStatic("someVar"))
}
}
}

// MARK: - Known Failures

// https://github.com/apple/swift/issues/56165
Expand Down