@@ -81,10 +81,13 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
81
81
}
82
82
}
83
83
84
- private var root : Syntax {
85
- switch info. info! {
86
- case . root( _) : return self
87
- case . nonRoot( let info) : return info. parent. root
84
+ public var root : Syntax {
85
+ return withUnownedSyntax ( self ) {
86
+ var node = $0
87
+ while let parent = node. parent {
88
+ node = parent
89
+ }
90
+ return node. value
88
91
}
89
92
}
90
93
@@ -129,7 +132,8 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
129
132
}
130
133
131
134
/// "designated" memberwise initializer of `Syntax`.
132
- init ( _ raw: RawSyntax , info: Info ) {
135
+ @_transparent
136
+ init ( _ raw: RawSyntax , info: __shared Info) {
133
137
self . raw = raw
134
138
self . info = info
135
139
}
@@ -309,7 +313,7 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
309
313
/// Create a ``Syntax`` node from a specialized syntax node.
310
314
// Inline always so the optimizer can optimize this to a member access on `syntax` without having to go through
311
315
// generics.
312
- @inline ( __always )
316
+ @_transparent
313
317
public init ( _ syntax: __shared some SyntaxProtocol ) {
314
318
self = syntax. _syntaxNode
315
319
}
@@ -380,6 +384,57 @@ extension Syntax {
380
384
}
381
385
}
382
386
387
+ /// Temporary non-owning Syntax.
388
+ ///
389
+ /// This can be used for handling Syntax node without ARC traffic.
390
+ struct UnownedSyntax {
391
+ var raw : RawSyntax
392
+ var info : Unmanaged < Syntax . Info >
393
+
394
+ @_transparent
395
+ init ( _ node: __shared Syntax) {
396
+ self . raw = node. raw
397
+ self . info = . passUnretained( node. info. unsafelyUnwrapped)
398
+ }
399
+
400
+ /// Extract the Syntax value.
401
+ @inline ( __always)
402
+ var value : Syntax {
403
+ Syntax ( raw, info: info. takeUnretainedValue ( ) )
404
+ }
405
+
406
+ /// Get the parent of the Syntax value, but without retaining it.
407
+ @inline ( __always)
408
+ var parent : UnownedSyntax ? {
409
+ return info. _withUnsafeGuaranteedRef {
410
+ switch $0. info. unsafelyUnwrapped {
411
+ case . nonRoot( let info) :
412
+ return UnownedSyntax ( info. parent)
413
+ case . root( _) :
414
+ return nil
415
+ }
416
+ }
417
+ }
418
+
419
+ /// Temporarily use the Syntax value.
420
+ @inline ( __always)
421
+ func withValue< T> ( _ body: ( Syntax ) -> T ) -> T {
422
+ info. _withUnsafeGuaranteedRef {
423
+ body ( Syntax ( self . raw, info: $0) )
424
+ }
425
+ }
426
+ }
427
+
428
+ /// Execute the `body` with ``UnownedSyntax`` of `node`.
429
+ ///
430
+ /// This guarantees the life time of the `node` during the `body` is executed.
431
+ @inline ( __always)
432
+ func withUnownedSyntax< T> ( _ node: some SyntaxProtocol , _ body: ( UnownedSyntax ) -> T ) -> T {
433
+ return withExtendedLifetime ( node) {
434
+ body ( UnownedSyntax ( Syntax ( $0) ) )
435
+ }
436
+ }
437
+
383
438
/// ``SyntaxNode`` used to be a pervasive type name in SwiftSyntax that has been
384
439
/// replaced by the ``Syntax`` type.
385
440
@available ( * , unavailable, message: " use 'Syntax' instead " )
0 commit comments