@@ -43,7 +43,11 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
43
43
44
44
/// Lists the expressions that have been visited, from the outermost expression, where contextual
45
45
/// breaks and start/end contextual breaking tokens have been inserted.
46
- private var preVisitedExprs = Set < ExprSyntax > ( )
46
+ private var preVisitedExprs = Set < SyntaxIdentifier > ( )
47
+
48
+ /// Tracks the "root" exprs where previsiting for contextual breaks started so that
49
+ /// `preVisitedExprs` can be emptied after exiting an expr tree.
50
+ private var rootExprs = Set < SyntaxIdentifier > ( )
47
51
48
52
/// Lists the tokens that are the closing or final delimiter of a node that shouldn't be split
49
53
/// from the preceding token. When breaks are inserted around compound expressions, the breaks are
@@ -850,6 +854,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
850
854
return . visitChildren
851
855
}
852
856
857
+ override func visitPost( _ node: MemberAccessExprSyntax ) {
858
+ clearContextualBreakState ( node)
859
+ }
860
+
853
861
override func visit( _ node: FunctionCallExprSyntax ) -> SyntaxVisitorContinueKind {
854
862
preVisitInsertingContextualBreaks ( node)
855
863
@@ -881,6 +889,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
881
889
return . visitChildren
882
890
}
883
891
892
+ override func visitPost( _ node: FunctionCallExprSyntax ) {
893
+ clearContextualBreakState ( node)
894
+ }
895
+
884
896
/// Arrange the given argument list (or equivalently, tuple expression list) as a list of function
885
897
/// arguments.
886
898
///
@@ -1076,6 +1088,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
1076
1088
return . visitChildren
1077
1089
}
1078
1090
1091
+ override func visitPost( _ node: SubscriptExprSyntax ) {
1092
+ clearContextualBreakState ( node)
1093
+ }
1094
+
1079
1095
override func visit( _ node: ExpressionSegmentSyntax ) -> SyntaxVisitorContinueKind {
1080
1096
// TODO: For now, just use the raw text of the node and don't try to format it deeper. In the
1081
1097
// future, we should find a way to format the expression but without wrapping so that at least
@@ -2271,7 +2287,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
2271
2287
2272
2288
/// Appends the before-tokens of the given syntax token to the token stream.
2273
2289
private func appendBeforeTokens( _ token: TokenSyntax ) {
2274
- if let before = beforeMap [ token] {
2290
+ if let before = beforeMap. removeValue ( forKey : token) {
2275
2291
before. forEach ( appendToken)
2276
2292
}
2277
2293
}
@@ -2331,7 +2347,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
2331
2347
/// not incorrectly inserted into the token stream *after* a break or newline.
2332
2348
private func appendAfterTokensAndTrailingComments( _ token: TokenSyntax ) {
2333
2349
let ( wasLineComment, trailingCommentTokens) = afterTokensForTrailingComment ( token)
2334
- let afterGroups = afterMap [ token] ?? [ ]
2350
+ let afterGroups = afterMap. removeValue ( forKey : token) ?? [ ]
2335
2351
var hasAppendedTrailingComment = false
2336
2352
2337
2353
if !wasLineComment {
@@ -3177,23 +3193,34 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
3177
3193
appendToken ( . break( . same, size: 0 ) )
3178
3194
}
3179
3195
3196
+ /// Cleans up state related to inserting contextual breaks throughout expressions during
3197
+ /// `visitPost` for an expression that is the root of an expression tree.
3198
+ private func clearContextualBreakState< T: ExprSyntaxProtocol > ( _ expr: T ) {
3199
+ let exprID = expr. id
3200
+ if rootExprs. remove ( exprID) != nil {
3201
+ preVisitedExprs. removeAll ( )
3202
+ }
3203
+ }
3204
+
3180
3205
/// Visits the given expression node and all of the nested expression nodes, inserting tokens
3181
3206
/// necessary for contextual breaking throughout the expression. Records the nodes that were
3182
3207
/// visited so that they can be skipped later.
3183
3208
private func preVisitInsertingContextualBreaks< T: ExprSyntaxProtocol & Equatable > ( _ expr: T ) {
3184
- let exprSyntax = ExprSyntax ( expr)
3185
- if !preVisitedExprs. contains ( exprSyntax ) {
3186
- let ( visited , _ , _ ) = insertContextualBreaks ( exprSyntax , isTopLevel : true )
3187
- preVisitedExprs . formUnion ( visited )
3209
+ let exprID = expr. id
3210
+ if !preVisitedExprs. contains ( exprID ) {
3211
+ rootExprs . insert ( exprID )
3212
+ insertContextualBreaks ( ExprSyntax ( expr ) , isTopLevel : true )
3188
3213
}
3189
3214
}
3190
3215
3191
3216
/// Recursively visits nested expressions from the given expression inserting contextual breaking
3192
3217
/// tokens. When visiting an expression node, `preVisitInsertingContextualBreaks(_:)` should be
3193
3218
/// called instead of this helper.
3219
+ @discardableResult
3194
3220
private func insertContextualBreaks( _ expr: ExprSyntax , isTopLevel: Bool ) -> (
3195
- [ ExprSyntax ] , hasCompoundExpression: Bool , hasMemberAccess: Bool
3221
+ hasCompoundExpression: Bool , hasMemberAccess: Bool
3196
3222
) {
3223
+ preVisitedExprs. insert ( expr. id)
3197
3224
if let memberAccessExpr = expr. as ( MemberAccessExprSyntax . self) {
3198
3225
// When the member access is part of a calling expression, the break before the dot is
3199
3226
// inserted when visiting the parent node instead so that the break is inserted before any
@@ -3202,21 +3229,18 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
3202
3229
expr. parent? . isProtocol ( CallingExprSyntaxProtocol . self) != true {
3203
3230
before ( memberAccessExpr. dot, tokens: . break( . contextual, size: 0 ) )
3204
3231
}
3205
- let children : [ ExprSyntax ]
3206
3232
var hasCompoundExpression = false
3207
3233
if let base = memberAccessExpr. base {
3208
- ( children, hasCompoundExpression, _) = insertContextualBreaks ( base, isTopLevel: false )
3209
- } else {
3210
- children = [ ]
3234
+ ( hasCompoundExpression, _) = insertContextualBreaks ( base, isTopLevel: false )
3211
3235
}
3212
3236
if isTopLevel {
3213
3237
before ( expr. firstToken, tokens: . contextualBreakingStart)
3214
3238
after ( expr. lastToken, tokens: . contextualBreakingEnd)
3215
3239
}
3216
- return ( [ expr ] + children , hasCompoundExpression, true )
3240
+ return ( hasCompoundExpression, true )
3217
3241
} else if let callingExpr = expr. asProtocol ( CallingExprSyntaxProtocol . self) {
3218
3242
let calledExpression = callingExpr. calledExpression
3219
- let ( children , hasCompoundExpression, hasMemberAccess) =
3243
+ let ( hasCompoundExpression, hasMemberAccess) =
3220
3244
insertContextualBreaks ( calledExpression, isTopLevel: false )
3221
3245
3222
3246
let shouldGroup =
@@ -3241,7 +3265,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
3241
3265
before ( expr. firstToken, tokens: beforeTokens)
3242
3266
after ( expr. lastToken, tokens: afterTokens)
3243
3267
}
3244
- return ( [ expr ] + children , true , hasMemberAccess)
3268
+ return ( true , hasMemberAccess)
3245
3269
}
3246
3270
3247
3271
// Otherwise, it's an expression that isn't calling another expression (e.g. array or
@@ -3250,7 +3274,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
3250
3274
before ( expr. firstToken, tokens: . contextualBreakingStart)
3251
3275
after ( expr. lastToken, tokens: . contextualBreakingEnd)
3252
3276
let hasCompoundExpression = !expr. is ( IdentifierExprSyntax . self)
3253
- return ( [ expr ] , hasCompoundExpression, false )
3277
+ return ( hasCompoundExpression, false )
3254
3278
}
3255
3279
}
3256
3280
0 commit comments