diff --git a/CHANGELOG.md b/CHANGELOG.md index 21cf1b5bf..b85ab24f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ ##### Bug Fixes -- None. +- Fix retaining members of public generic protocol extensions with `--retain-public`. ## 2.15.1 (2023-09-17) diff --git a/Sources/PeripheryKit/Syntax/DeclarationSyntaxVisitor.swift b/Sources/PeripheryKit/Syntax/DeclarationSyntaxVisitor.swift index dc3a08b2a..d8e988075 100644 --- a/Sources/PeripheryKit/Syntax/DeclarationSyntaxVisitor.swift +++ b/Sources/PeripheryKit/Syntax/DeclarationSyntaxVisitor.swift @@ -103,6 +103,11 @@ final class DeclarationSyntaxVisitor: PeripherySyntaxVisitor { if let memberType = node.extendedType.as(MemberTypeSyntax.self) { position = memberType.name.positionAfterSkippingLeadingTrivia + } else if let genericArgumentClause = node.extendedType.as(IdentifierTypeSyntax.self)?.genericArgumentClause { + // Generic protocol extensions in the form `extension Foo` have incorrect locations in the index store. + // This results in syntax metadata not being applied to the declaration due to the location mismatch. To + // workaround this, parse this node with the incorrect location. + position = genericArgumentClause.rightAngle.positionAfterSkippingLeadingTrivia } parse( diff --git a/Tests/Fixtures/RetentionFixtures/testRetainsGenericProtocolExtensionMembers.swift b/Tests/Fixtures/RetentionFixtures/testRetainsGenericProtocolExtensionMembers.swift new file mode 100644 index 000000000..0ddb043ee --- /dev/null +++ b/Tests/Fixtures/RetentionFixtures/testRetainsGenericProtocolExtensionMembers.swift @@ -0,0 +1,25 @@ +public protocol FixtureProtocol38 { + associatedtype Value +} + +public extension FixtureProtocol38 { + func someFunc() {} +} + +public protocol FixtureProtocol39 { + associatedtype Value + associatedtype Value2 +} + +public extension FixtureProtocol39 { + func someFunc() {} +} + +public protocol FixtureProtocol40 { + associatedtype Value + associatedtype Value2 +} + +public extension FixtureProtocol40 where Value == Int, Value2 == Int { + func someFunc() {} +} diff --git a/Tests/PeripheryTests/RetentionTest.swift b/Tests/PeripheryTests/RetentionTest.swift index ea1136b39..79340bdfa 100644 --- a/Tests/PeripheryTests/RetentionTest.swift +++ b/Tests/PeripheryTests/RetentionTest.swift @@ -476,6 +476,25 @@ final class RetentionTest: FixtureSourceGraphTestCase { } } + func testRetainsGenericProtocolExtensionMembers() { + analyze(retainPublic: true) { + assertReferenced(.protocol("FixtureProtocol38")) + assertReferenced(.extensionProtocol("FixtureProtocol38")) { + self.assertReferenced(.functionMethodInstance("someFunc()")) + } + + assertReferenced(.protocol("FixtureProtocol39")) + assertReferenced(.extensionProtocol("FixtureProtocol39")) { + self.assertReferenced(.functionMethodInstance("someFunc()")) + } + + assertReferenced(.protocol("FixtureProtocol40")) + assertReferenced(.extensionProtocol("FixtureProtocol40")) { + self.assertReferenced(.functionMethodInstance("someFunc()")) + } + } + } + func testUnusedTypealias() { analyze() { assertNotReferenced(.typealias("UnusedAlias"))