@@ -25,59 +25,116 @@ public final class AlwaysUseLiteralForEmptyArrayInit : SyntaxFormatRule {
25
25
public override class var isOptIn : Bool { return true }
26
26
27
27
public override func visit( _ node: PatternBindingSyntax ) -> PatternBindingSyntax {
28
- guard let initializer = node. initializer else {
29
- return node
30
- }
31
-
32
28
// Check whether the initializer is `[<Type>]()`
33
- guard let initCall = initializer . value . as ( FunctionCallExprSyntax . self ) ,
34
- var arrayLiteral = initCall . calledExpression . as ( ArrayExprSyntax . self) ,
29
+ guard let initializer = node . initializer ,
30
+ let initCall = initializer . value . as ( FunctionCallExprSyntax . self) ,
35
31
initCall. arguments. isEmpty else {
36
32
return node
37
33
}
38
34
39
- guard let elementType = getElementType ( arrayLiteral) else {
40
- return node
35
+ if let arrayLiteral = initCall. calledExpression. as ( ArrayExprSyntax . self) ,
36
+ let type = getLiteralType ( arrayLiteral) {
37
+ return rewrite ( node, type: type)
38
+ }
39
+
40
+ if let dictLiteral = initCall. calledExpression. as ( DictionaryExprSyntax . self) ,
41
+ let type = getLiteralType ( dictLiteral) {
42
+ return rewrite ( node, type: type)
41
43
}
42
44
45
+ return node
46
+ }
47
+
48
+ private func rewrite( _ node: PatternBindingSyntax ,
49
+ type: ArrayTypeSyntax ) -> PatternBindingSyntax {
43
50
var replacement = node
44
51
45
- var withFixIt = " [] "
52
+ diagnose ( node, type: type)
53
+
46
54
if replacement. typeAnnotation == nil {
47
- withFixIt = " : [ \( elementType) ] = [] "
55
+ // Drop trailing trivia after pattern because ':' has to appear connected to it.
56
+ replacement. pattern = node. pattern. with ( \. trailingTrivia, [ ] )
57
+ // Add explicit type annotiation: ': [<Type>]`
58
+ replacement. typeAnnotation = . init( type: type. with ( \. leadingTrivia, . space)
59
+ . with ( \. trailingTrivia, . space) )
48
60
}
49
61
50
- diagnose ( . refactorEmptyArrayInit( replace: " \( initCall) " , with: withFixIt) , on: initCall)
62
+ let initializer = node. initializer!
63
+ let emptyArrayExpr = ArrayExprSyntax ( elements: ArrayElementListSyntax . init ( [ ] ) )
64
+
65
+ // Replace initializer call with empty array literal: `[<Type>]()` -> `[]`
66
+ replacement. initializer = initializer. with ( \. value, ExprSyntax ( emptyArrayExpr) )
67
+
68
+ return replacement
69
+ }
70
+
71
+ private func rewrite( _ node: PatternBindingSyntax ,
72
+ type: DictionaryTypeSyntax ) -> PatternBindingSyntax {
73
+ var replacement = node
74
+
75
+ diagnose ( node, type: type)
51
76
52
77
if replacement. typeAnnotation == nil {
53
78
// Drop trailing trivia after pattern because ':' has to appear connected to it.
54
79
replacement. pattern = node. pattern. with ( \. trailingTrivia, [ ] )
55
80
// Add explicit type annotiation: ': [<Type>]`
56
- replacement. typeAnnotation = . init( type: ArrayTypeSyntax ( leadingTrivia: . space,
57
- element: elementType,
58
- trailingTrivia: . space) )
81
+ replacement. typeAnnotation = . init( type: type. with ( \. leadingTrivia, . space)
82
+ . with ( \. trailingTrivia, . space) )
59
83
}
60
84
61
- // Replace initializer call with empty array literal: `[<Type>]()` -> `[]`
62
- arrayLiteral. elements = ArrayElementListSyntax . init ( [ ] )
63
- replacement. initializer = initializer. with ( \. value, ExprSyntax ( arrayLiteral) )
85
+ let initializer = node. initializer!
86
+ let emptyDictExpr = DictionaryExprSyntax ( content: . colon( . colonToken( ) ) )
87
+
88
+ // Replace initializer call with empty dictionary literal: `[<Type>]()` -> `[]`
89
+ replacement. initializer = initializer. with ( \. value, ExprSyntax ( emptyDictExpr) )
64
90
65
91
return replacement
66
92
}
67
93
68
- private func getElementType( _ arrayLiteral: ArrayExprSyntax ) -> TypeSyntax ? {
69
- guard let elementExpr = arrayLiteral. elements. firstAndOnly? . as ( ArrayElementSyntax . self) else {
94
+ private func diagnose( _ node: PatternBindingSyntax , type: ArrayTypeSyntax ) {
95
+ var withFixIt = " [] "
96
+ if node. typeAnnotation == nil {
97
+ withFixIt = " : \( type) = [] "
98
+ }
99
+
100
+ let initCall = node. initializer!. value
101
+ emitDiagnostic ( replace: " \( initCall) " , with: withFixIt, on: initCall)
102
+ }
103
+
104
+ private func diagnose( _ node: PatternBindingSyntax , type: DictionaryTypeSyntax ) {
105
+ var withFixIt = " [:] "
106
+ if node. typeAnnotation == nil {
107
+ withFixIt = " : \( type) = [:] "
108
+ }
109
+
110
+ let initCall = node. initializer!. value
111
+ emitDiagnostic ( replace: " \( initCall) " , with: withFixIt, on: initCall)
112
+ }
113
+
114
+ private func emitDiagnostic( replace: String , with fixIt: String , on: ExprSyntax ? ) {
115
+ diagnose ( . refactorIntoEmptyLiteral( replace: replace, with: fixIt) , on: on)
116
+ }
117
+
118
+ private func getLiteralType( _ arrayLiteral: ArrayExprSyntax ) -> ArrayTypeSyntax ? {
119
+ guard let elementExpr = arrayLiteral. elements. firstAndOnly,
120
+ elementExpr. is ( ArrayElementSyntax . self) else {
70
121
return nil
71
122
}
72
123
73
- var parser = Parser ( elementExpr. description)
124
+ var parser = Parser ( arrayLiteral. description)
125
+ let elementType = TypeSyntax . parse ( from: & parser)
126
+ return elementType. hasError ? nil : elementType. as ( ArrayTypeSyntax . self)
127
+ }
128
+
129
+ private func getLiteralType( _ dictLiteral: DictionaryExprSyntax ) -> DictionaryTypeSyntax ? {
130
+ var parser = Parser ( dictLiteral. description)
74
131
let elementType = TypeSyntax . parse ( from: & parser)
75
- return elementType. hasError ? nil : elementType
132
+ return elementType. hasError ? nil : elementType. as ( DictionaryTypeSyntax . self )
76
133
}
77
134
}
78
135
79
136
extension Finding . Message {
80
- public static func refactorEmptyArrayInit ( replace: String , with: String ) -> Finding . Message {
137
+ public static func refactorIntoEmptyLiteral ( replace: String , with: String ) -> Finding . Message {
81
138
" replace ' \( replace) ' with ' \( with) ' "
82
139
}
83
140
}
0 commit comments