@@ -361,16 +361,23 @@ extension RawSyntax {
361361}
362362
363363extension 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 {
365369 if let syntaxText = storedText {
366- try body ( syntaxText)
370+ try body ( syntaxText, /*isEphemeral*/ false )
367371 return
368372 }
369373
370374 var description = " "
371375 write ( to: & description)
372376 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+ )
374381 }
375382 }
376383}
@@ -382,21 +389,21 @@ extension RawSyntax {
382389 /// Unlike `description`, this provides a source-accurate representation
383390 /// even in the presence of malformed UTF-8 in the input source.
384391 ///
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 {
389396 switch rawData. payload {
390397 case . parsedToken( let dat) :
391398 if dat. presence == . present {
392- try body ( dat. wholeText)
399+ try body ( dat. wholeText, /*isEphemeral*/ false )
393400 }
394401 case . materializedToken( let dat) :
395402 if dat. presence == . present {
396403 for p in dat. leadingTrivia {
397404 try p. withSyntaxText ( body: body)
398405 }
399- try body ( dat. tokenText)
406+ try body ( dat. tokenText, /*isEphemeral*/ false )
400407 for p in dat. trailingTrivia {
401408 try p. withSyntaxText ( body: body)
402409 }
@@ -412,9 +419,20 @@ extension RawSyntax {
412419 /// source even in the presence of invalid UTF-8.
413420 public var syntaxTextBytes : [ UInt8 ] {
414421 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+ }
417434 }
435+ result. append ( contentsOf: buf)
418436 return result
419437 }
420438}
0 commit comments