@@ -361,16 +361,23 @@ extension RawSyntax {
361
361
}
362
362
363
363
extension RawTriviaPiece {
364
- func withSyntaxText( body: ( SyntaxText ) throws -> Void ) rethrows {
364
+ /// Call `body` with the syntax text of this trivia piece.
365
+ ///
366
+ /// If `isEphemeral` is `true`, the ``SyntaxText`` argument is only guaranteed
367
+ /// to be valid within the call.
368
+ func withSyntaxText( body: ( SyntaxText , _ isEphemeral: Bool ) throws -> Void ) rethrows {
365
369
if let syntaxText = storedText {
366
- try body ( syntaxText)
370
+ try body ( syntaxText, /*isEphemeral*/ false )
367
371
return
368
372
}
369
373
370
374
var description = " "
371
375
write ( to: & description)
372
376
try description. withUTF8 { buffer in
373
- try body ( SyntaxText ( baseAddress: buffer. baseAddress, count: buffer. count) )
377
+ try body (
378
+ SyntaxText ( baseAddress: buffer. baseAddress, count: buffer. count) ,
379
+ /*isEphemeral*/ true
380
+ )
374
381
}
375
382
}
376
383
}
@@ -382,21 +389,21 @@ extension RawSyntax {
382
389
/// Unlike `description`, this provides a source-accurate representation
383
390
/// even in the presence of malformed UTF-8 in the input source.
384
391
///
385
- /// The `` SyntaxText`` arguments passed to the visitor are only guaranteed
386
- /// to be valid within that call. It is unsafe to escape the `SyntaxValue`
387
- /// values outside of the closure .
388
- public func withEachSyntaxText( body: ( SyntaxText ) throws -> Void ) rethrows {
392
+ /// If `isEphemeral` is `true`, the `` SyntaxText`` arguments passed to the
393
+ /// visitor are only guaranteed to be valid within that call. Otherwise, they
394
+ /// are valid as long as the raw syntax is alive .
395
+ public func withEachSyntaxText( body: ( SyntaxText , _ isEphemeral : Bool ) throws -> Void ) rethrows {
389
396
switch rawData. payload {
390
397
case . parsedToken( let dat) :
391
398
if dat. presence == . present {
392
- try body ( dat. wholeText)
399
+ try body ( dat. wholeText, /*isEphemeral*/ false )
393
400
}
394
401
case . materializedToken( let dat) :
395
402
if dat. presence == . present {
396
403
for p in dat. leadingTrivia {
397
404
try p. withSyntaxText ( body: body)
398
405
}
399
- try body ( dat. tokenText)
406
+ try body ( dat. tokenText, /*isEphemeral*/ false )
400
407
for p in dat. trailingTrivia {
401
408
try p. withSyntaxText ( body: body)
402
409
}
@@ -412,9 +419,20 @@ extension RawSyntax {
412
419
/// source even in the presence of invalid UTF-8.
413
420
public var syntaxTextBytes : [ UInt8 ] {
414
421
var result : [ UInt8 ] = [ ]
415
- withEachSyntaxText { syntaxText in
416
- result. append ( contentsOf: syntaxText)
422
+ var buf : SyntaxText = " "
423
+ withEachSyntaxText { syntaxText, isEphemeral in
424
+ if isEphemeral {
425
+ result. append ( contentsOf: buf)
426
+ result. append ( contentsOf: syntaxText)
427
+ buf = " "
428
+ } else if let base = buf. baseAddress, base + buf. count == syntaxText. baseAddress {
429
+ buf = SyntaxText ( baseAddress: base, count: buf. count + syntaxText. count)
430
+ } else {
431
+ result. append ( contentsOf: buf)
432
+ buf = syntaxText
433
+ }
417
434
}
435
+ result. append ( contentsOf: buf)
418
436
return result
419
437
}
420
438
}
0 commit comments