Skip to content

Commit

Permalink
Merge pull request #241 from uber/bugfix-generic-same-method-name
Browse files Browse the repository at this point in the history
[Bugfix] Fix functions with same signature and different generic constraints not getting generated
  • Loading branch information
ryanaveo authored Jun 12, 2023
2 parents e51ab9a + fdc5ac7 commit c1b8b05
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 1 deletion.
38 changes: 37 additions & 1 deletion Sources/MockoloFramework/Models/MethodModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,40 @@ final class MethodModel: Model {
private var staticKind: String {
return isStatic ? .static : ""
}

/// This is used to uniquely identify methods with the same signature and different generic requirements
var genericWhereClauseToSignatureComponent: String {
guard let genericWhereClause else {
return ""
}
let typeRequirementSyntax = ":"
let typeEqualitySyntax = "=="

var signatureComponents: [String] = []

genericWhereClause.deletingPrefix("where").components(separatedBy: ",").forEach { requirement in
if requirement.contains(typeRequirementSyntax) {
let components = requirement.components(separatedBy: typeRequirementSyntax).map{ $0.trimmingCharacters(in: .whitespaces) }
guard let key = components.first, let value = components.last else {
return
}
let valueDescription = value.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "&", with: "And")
signatureComponents.append(contentsOf: [key, valueDescription])
} else if requirement.contains(typeEqualitySyntax) {
let components = requirement.components(separatedBy: typeEqualitySyntax).map{ $0.trimmingCharacters(in: .whitespaces) }
guard let key = components.first, let value = components.last else {
return
}
signatureComponents.append(contentsOf: [key, value])
}
}

return signatureComponents.map { component in
var newComponent = component
newComponent.removeAll(where: { $0 == "."})
return newComponent
}.joined()
}

var isInitializer: Bool {
if case .initKind(_, _) = kind {
Expand Down Expand Up @@ -79,7 +113,9 @@ final class MethodModel: Model {

let genericTypeNames = self.genericTypeParams.map { $0.name.capitalizeFirstLetter + $0.type.displayName }
args.append(contentsOf: genericTypeNames)

if let genericWhereClause {
args.append(genericWhereClauseToSignatureComponent)
}
args.append(contentsOf: paramTypes.map(\.displayName))
var displayType = self.type.displayName
let capped = min(displayType.count, 32)
Expand Down
5 changes: 5 additions & 0 deletions Sources/MockoloFramework/Utils/StringExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ extension String {
}
return !argsMap.isEmpty ? argsMap : nil
}

func deletingPrefix(_ prefix: String) -> String {
guard self.hasPrefix(prefix) else { return self }
return String(self.dropFirst(prefix.count))
}
}

let separatorsForDisplay = CharacterSet(charactersIn: "<>[] :,()_-.&@#!{}@+\"\'")
Expand Down
113 changes: 113 additions & 0 deletions Tests/TestFuncs/TestGenericFuncs/FixtureGenericFunc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,116 @@ class NetworkingMock: Networking {
}
"""

let funcDuplicateSignatureDifferentWhereClause = """
/// \(String.mockAnnotation)
protocol Storing {
func connect<T>(adapter: T) where T: Adapter
func connect<T>(adapter: T) where T: KeyedAdapter
func connect<T>(adapter: T) where T: KeyedAdapter2
func connect<T>(adapter: T) where T: KeyedAdapter3
}
"""

let funcDuplicateSignatureDifferentWhereClauseMock = """
class StoringMock: Storing {
init() { }
private(set) var connectCallCount = 0
var connectHandler: ((Any) -> ())?
func connect<T>(adapter: T) where T: Adapter {
connectCallCount += 1
if let connectHandler = connectHandler {
connectHandler(adapter)
}
}
private(set) var connectAdapterCallCount = 0
var connectAdapterHandler: ((Any) -> ())?
func connect<T>(adapter: T) where T: KeyedAdapter {
connectAdapterCallCount += 1
if let connectAdapterHandler = connectAdapterHandler {
connectAdapterHandler(adapter)
}
}
private(set) var connectAdapterTCallCount = 0
var connectAdapterTHandler: ((Any) -> ())?
func connect<T>(adapter: T) where T: KeyedAdapter2 {
connectAdapterTCallCount += 1
if let connectAdapterTHandler = connectAdapterTHandler {
connectAdapterTHandler(adapter)
}
}
private(set) var connectAdapterTTKeyedAdapter3CallCount = 0
var connectAdapterTTKeyedAdapter3Handler: ((Any) -> ())?
func connect<T>(adapter: T) where T: KeyedAdapter3 {
connectAdapterTTKeyedAdapter3CallCount += 1
if let connectAdapterTTKeyedAdapter3Handler = connectAdapterTTKeyedAdapter3Handler {
connectAdapterTTKeyedAdapter3Handler(adapter)
}
}
}
"""

let funcDuplicateSignatureDifferentWhereClauseEquality = """
/// \(String.mockAnnotation)
protocol Storing<S: Sequence> {
func connect<T>(adapter: T) where T: Adapter, T.Element == S.Element
func connect<T>(adapter: T) where T: KeyedAdapter, T.Element == S.Element
func connect<T>(adapter: T) where T: KeyedAdapter2, T.Element == S.Element
func connect<T>(adapter: T) where T: KeyedAdapter3, T.Element == S.Element
}
"""

let funcDuplicateSignatureDifferentWhereClauseEqualityMock = """
class StoringMock: Storing {
init() { }
private(set) var connectCallCount = 0
var connectHandler: ((Any) -> ())?
func connect<T>(adapter: T) where T: Adapter, T.Element == S.Element {
connectCallCount += 1
if let connectHandler = connectHandler {
connectHandler(adapter)
}
}
private(set) var connectAdapterCallCount = 0
var connectAdapterHandler: ((Any) -> ())?
func connect<T>(adapter: T) where T: KeyedAdapter, T.Element == S.Element {
connectAdapterCallCount += 1
if let connectAdapterHandler = connectAdapterHandler {
connectAdapterHandler(adapter)
}
}
private(set) var connectAdapterTCallCount = 0
var connectAdapterTHandler: ((Any) -> ())?
func connect<T>(adapter: T) where T: KeyedAdapter2, T.Element == S.Element {
connectAdapterTCallCount += 1
if let connectAdapterTHandler = connectAdapterTHandler {
connectAdapterTHandler(adapter)
}
}
private(set) var connectAdapterTTKeyedAdapter3TElementSElementCallCount = 0
var connectAdapterTTKeyedAdapter3TElementSElementHandler: ((Any) -> ())?
func connect<T>(adapter: T) where T: KeyedAdapter3, T.Element == S.Element {
connectAdapterTTKeyedAdapter3TElementSElementCallCount += 1
if let connectAdapterTTKeyedAdapter3TElementSElementHandler = connectAdapterTTKeyedAdapter3TElementSElementHandler {
connectAdapterTTKeyedAdapter3TElementSElementHandler(adapter)
}
}
}
"""
10 changes: 10 additions & 0 deletions Tests/TestFuncs/TestGenericFuncs/GenericFuncTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ class GenericFuncTests: MockoloTestCase {
verify(srcContent: funcWhereClause,
dstContent: funcWhereClauseMock)
}

func testWhereClauseWithSameSignature() {
verify(srcContent: funcDuplicateSignatureDifferentWhereClause,
dstContent: funcDuplicateSignatureDifferentWhereClauseMock)
}

func testWhereClauseWithSameSignatureAndEqualityConstraints() {
verify(srcContent: funcDuplicateSignatureDifferentWhereClauseEquality,
dstContent: funcDuplicateSignatureDifferentWhereClauseEqualityMock)
}
}


0 comments on commit c1b8b05

Please sign in to comment.