diff --git a/Sources/Rules/SimplifyGenericConstraints.swift b/Sources/Rules/SimplifyGenericConstraints.swift index 5edb852d..fe224eb1 100644 --- a/Sources/Rules/SimplifyGenericConstraints.swift +++ b/Sources/Rules/SimplifyGenericConstraints.swift @@ -134,6 +134,16 @@ extension Formatter { constraintsByType[item.genericType.name, default: []].append(item.conformance) } + // Check if any combined protocol composition is over 40 characters + // If so, skip simplification for the entire declaration + for conformances in constraintsByType.values { + let protocolNames = conformances.map(\.name) + let combinedComposition = protocolNames.joined(separator: " & ") + if combinedComposition.count > 40 { + return + } + } + // We perform modifications in reverse order to avoid invalidating indices // First, remove constraints from the where clause diff --git a/Tests/Rules/SimplifyGenericConstraintsTests.swift b/Tests/Rules/SimplifyGenericConstraintsTests.swift index 28097b9e..f32615e0 100644 --- a/Tests/Rules/SimplifyGenericConstraintsTests.swift +++ b/Tests/Rules/SimplifyGenericConstraintsTests.swift @@ -326,6 +326,21 @@ final class SimplifyGenericConstraintsTests: XCTestCase { testFormatting(for: input, output, rule: .simplifyGenericConstraints, exclude: [.unusedArguments, .indent]) } + func testDoesNotSimplifyWhenCombinedCompositionIsTooLong() { + // When multiple constraints for the same type are combined with &, + // don't simplify if the result is over 40 characters + let input = """ + func transform(_ a: A, _ b: B, _ c: C, _ d: D) + where A: VeryLongProtocolName, + A: AnotherVeryLongProtocolName, + B: Collection, + C: Comparable, + D: Sequence + {} + """ + testFormatting(for: input, rule: .simplifyGenericConstraints, exclude: [.unusedArguments, .indent]) + } + // MARK: - Constraints on generics not in parameter list func testPreserveConstraintsForGenericsNotInParameterList() { @@ -398,4 +413,26 @@ final class SimplifyGenericConstraintsTests: XCTestCase { """ testFormatting(for: input, rule: .simplifyGenericConstraints, exclude: [.indent, .emptyBraces]) } + + func testDoesNotSimplifyLongProtocolComposition() { + // Don't simplify when protocol composition is over 40 characters + // This prevents awkward line breaks when wrapArguments is applied + let input = """ + enum Foo: SomeProtocol where + T: ProtocolA & SomeModule.ProtocolB & ProtocolC + { + } + """ + testFormatting(for: input, rule: .simplifyGenericConstraints, exclude: [.indent, .emptyBraces]) + } + + func testDoesNotSimplifySingleLongProtocolName() { + // Don't simplify when a single protocol name is over 40 characters + let input = """ + enum Foo: SomeProtocol where T: VeryLongProtocolNameThatIsOverFortyCharacters + { + } + """ + testFormatting(for: input, rule: .simplifyGenericConstraints, exclude: [.indent, .emptyBraces, .braces]) + } }