@@ -177,17 +177,19 @@ extension DeclSyntaxProtocol {
177
177
var signatureString : String {
178
178
return switch DeclSyntax ( self . detached) . as ( DeclSyntaxEnum . self) {
179
179
case . functionDecl( let node) :
180
- node. with ( \. body, nil ) . trimmedDescription
180
+ node. with ( \. body, nil ) . triviaSanitizedDescription
181
181
case . initializerDecl( let node) :
182
- node. with ( \. body, nil ) . trimmedDescription
182
+ node. with ( \. body, nil ) . triviaSanitizedDescription
183
183
case . classDecl( let node) :
184
- node. with ( \. memberBlock, " " ) . trimmedDescription
184
+ node. with ( \. memberBlock, " " ) . triviaSanitizedDescription
185
185
case . structDecl( let node) :
186
- node. with ( \. memberBlock, " " ) . trimmedDescription
186
+ node. with ( \. memberBlock, " " ) . triviaSanitizedDescription
187
187
case . protocolDecl( let node) :
188
- node. with ( \. memberBlock, " " ) . trimmedDescription
188
+ node. with ( \. memberBlock, " " ) . triviaSanitizedDescription
189
189
case . accessorDecl( let node) :
190
- node. with ( \. body, nil ) . trimmedDescription
190
+ node. with ( \. body, nil ) . triviaSanitizedDescription
191
+ case . subscriptDecl( let node) :
192
+ node. with ( \. accessorBlock, nil ) . triviaSanitizedDescription
191
193
case . variableDecl( let node) :
192
194
node
193
195
. with ( \. bindings, PatternBindingListSyntax (
@@ -197,9 +199,47 @@ extension DeclSyntaxProtocol {
197
199
. with ( \. initializer, nil )
198
200
}
199
201
) )
200
- . trimmedDescription
202
+ . triviaSanitizedDescription
201
203
default :
202
204
fatalError ( " unimplemented \( self . kind) " )
203
205
}
204
206
}
207
+
208
+ /// Syntax text but without unnecessary trivia.
209
+ ///
210
+ /// Connective trivia are condensed into a single whitespace, but no space
211
+ /// after opening or before closing parentheses
212
+ var triviaSanitizedDescription : String {
213
+ let visitor = TriviaSanitizingDescriptionVisitor ( viewMode: . sourceAccurate)
214
+ visitor. walk ( self . trimmed)
215
+ return visitor. result
216
+ }
217
+ }
218
+
219
+ class TriviaSanitizingDescriptionVisitor : SyntaxVisitor {
220
+ var result : String = " "
221
+
222
+ var prevTokenKind : TokenKind = . endOfFile
223
+ var prevHadTrailingSpace : Bool = false
224
+
225
+ override func visit( _ node: TokenSyntax ) -> SyntaxVisitorContinueKind {
226
+ let tokenKind = node. tokenKind
227
+ switch ( prevTokenKind, tokenKind) {
228
+ case
229
+ // No whitespace after open parentheses.
230
+ ( . leftAngle, _) , ( . leftParen, _) , ( . leftSquare, _) , ( . endOfFile, _) ,
231
+ // No whitespace before close parentheses.
232
+ ( _, . rightAngle) , ( _, . rightParen) , ( _, . rightSquare) :
233
+ break
234
+ default :
235
+ if prevHadTrailingSpace || !node. leadingTrivia. isEmpty {
236
+ result += " "
237
+ }
238
+ }
239
+ result += node. text
240
+ prevTokenKind = tokenKind
241
+ prevHadTrailingSpace = !node. trailingTrivia. isEmpty
242
+
243
+ return . skipChildren
244
+ }
205
245
}
0 commit comments