Skip to content

Commit 38f9a0d

Browse files
authored
Update propertyTypes rule to support Set literal initialization, in addition to arrays and dictionaries (#2189)
1 parent bff3f79 commit 38f9a0d

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

Sources/Rules/PropertyTypes.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ public extension FormatRule {
157157
formatter.replaceTokens(in: rhsExpressionRange, with: tokenize("\(type.string)()"))
158158
}
159159

160+
// Convert `let set: Set<Foo> = []` to `let set = Set<Foo>()`
161+
else if type.isSet,
162+
formatter.tokens[rhsStartIndex] == .startOfScope("["),
163+
let nextToken = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: rhsStartIndex),
164+
formatter.tokens[nextToken] == .endOfScope("]"),
165+
rhsExpressionRange.upperBound == nextToken
166+
{
167+
formatter.replaceTokens(in: rhsExpressionRange, with: tokenize("\(type.string)()"))
168+
}
169+
160170
else {
161171
return
162172
}
@@ -218,6 +228,11 @@ public extension FormatRule {
218228
formatter.replaceTokens(in: indexAfterType ... endOfInitCallScope, with: tokenize("[:]"))
219229
}
220230

231+
// If this is an empty set initializer, use `[]` instead of `.init()`
232+
else if rhsType.isSet, initializerHasNoArguments {
233+
formatter.replaceTokens(in: indexAfterType ... endOfInitCallScope, with: tokenize("[]"))
234+
}
235+
221236
else {
222237
formatter.insert([.operator(".", .prefix), .identifier("init")], at: indexAfterType)
223238
}

Sources/TypeName.swift

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,37 @@ extension TypeName {
8080
return !hasColonInBraces
8181
}
8282

83-
/// Whether or not this type is an array.
83+
/// Whether or not this type is a dictionary.
8484
var isDictionary: Bool {
8585
guard let openBrace = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: range.lowerBound - 1),
8686
formatter.tokens[openBrace] == .startOfScope("["),
8787
let closingBrace = formatter.endOfScope(at: openBrace),
8888
openBrace + 1 != closingBrace
8989
else { return false }
9090

91-
// [] would be a dictionary, not an array
91+
// [] would be an array, not a dictionary
9292
let hasColonInBraces = formatter.index(of: .delimiter(":"), in: (openBrace + 1) ..< closingBrace) != nil
9393
return hasColonInBraces
9494
}
9595

96+
/// Whether or not this type is a generic type with the given name.
97+
func isGenericType(named typeName: String) -> Bool {
98+
guard let firstToken = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: range.lowerBound - 1),
99+
formatter.tokens[firstToken] == .identifier(typeName),
100+
let openAngleBrace = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: firstToken),
101+
formatter.tokens[openAngleBrace] == .startOfScope("<"),
102+
let closingAngleBrace = formatter.endOfScope(at: openAngleBrace),
103+
openAngleBrace + 1 != closingAngleBrace
104+
else { return false }
105+
106+
return true
107+
}
108+
109+
/// Whether or not this type is a set.
110+
var isSet: Bool {
111+
isGenericType(named: "Set")
112+
}
113+
96114
/// Whether or not this type is a closure
97115
var isClosure: Bool {
98116
formatter.isStartOfClosureType(at: range.lowerBound)

Tests/Rules/PropertyTypesTests.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,4 +703,36 @@ class PropertyTypesTests: XCTestCase {
703703
let options = FormatOptions(propertyTypes: .inferred)
704704
testFormatting(for: input, output, rule: .propertyTypes, options: options)
705705
}
706+
707+
func testEmptySetLiteralToInferredType() {
708+
let input = """
709+
let set: Set<Int> = []
710+
var strings: Set<String> = []
711+
let nested: Set<Set<Bool>> = []
712+
"""
713+
let output = """
714+
let set = Set<Int>()
715+
var strings = Set<String>()
716+
let nested = Set<Set<Bool>>()
717+
"""
718+
let options = FormatOptions(propertyTypes: .inferred)
719+
testFormatting(for: input, output, rule: .propertyTypes, options: options)
720+
}
721+
722+
func testEmptySetInitToSetLiteral() {
723+
let input = """
724+
let set = Set<Foo>()
725+
var mapping = Set<String>()
726+
let nested = Set<Set<Int>>()
727+
let capacitySet = Set<Int>(minimumCapacity: 10)
728+
"""
729+
let output = """
730+
let set: Set<Foo> = []
731+
var mapping: Set<String> = []
732+
let nested: Set<Set<Int>> = []
733+
let capacitySet: Set<Int> = .init(minimumCapacity: 10)
734+
"""
735+
let options = FormatOptions(propertyTypes: .explicit)
736+
testFormatting(for: input, output, rule: .propertyTypes, options: options)
737+
}
706738
}

0 commit comments

Comments
 (0)