@@ -625,6 +625,10 @@ func assertParse<S: SyntaxProtocol>(
625625 )
626626 }
627627
628+ if expectedDiagnostics. isEmpty {
629+ assertBasicFormat ( source: source, parse: parse, file: file, line: line)
630+ }
631+
628632 #if SWIFTPARSER_ENABLE_ALTERNATE_TOKEN_INTROSPECTION
629633 if enableTestCaseMutation {
630634 let mutations : [ ( offset: Int , replacement: TokenSpec ) ] = parser. alternativeTokenChoices. flatMap { offset, replacements in
@@ -659,3 +663,54 @@ func assertParse<S: SyntaxProtocol>(
659663 }
660664 #endif
661665}
666+
667+ class TriviaRemover : SyntaxRewriter {
668+ override func visit( _ token: TokenSyntax ) -> TokenSyntax {
669+ var ancestor = Syntax ( token)
670+ while let parent = ancestor. parent {
671+ ancestor = parent
672+ if ancestor. is ( StringLiteralExprSyntax . self) || ancestor. is ( RegexLiteralExprSyntax . self) {
673+ // Don't mess with indentation inside string or regex literals.
674+ // BasicFormat doesn't know where to re-apply newlines and how much to indent the string literal contents.
675+ return token
676+ }
677+ }
678+ if token. parent? . is ( StringSegmentSyntax . self) ?? false {
679+ return token
680+ }
681+ return token. with ( \. leadingTrivia, [ ] ) . with ( \. trailingTrivia, [ ] )
682+ }
683+ }
684+
685+ func assertBasicFormat< S: SyntaxProtocol > (
686+ source: String ,
687+ parse: ( inout Parser ) -> S ,
688+ file: StaticString = #file,
689+ line: UInt = #line
690+ ) {
691+ var parser = Parser ( source)
692+ let sourceTree = Syntax ( parse ( & parser) )
693+ let withoutTrivia = TriviaRemover ( ) . visit ( sourceTree)
694+ let formatted = withoutTrivia. formatted ( )
695+
696+ var formattedParser = Parser ( formatted. description)
697+ let formattedReparsed = Syntax ( parse ( & formattedParser) )
698+
699+ do {
700+ let subtreeMatcher = SubtreeMatcher ( Syntax ( formattedReparsed) , markers: [ : ] )
701+ try subtreeMatcher. assertSameStructure (
702+ Syntax ( sourceTree) ,
703+ includeTrivia: false ,
704+ additionalInfo: """
705+ Removing trivia, formatting using BasicFormat and re-parsing did not produce the same syntax tree.
706+
707+ Formatted source:
708+ \( formatted)
709+ """ ,
710+ file: file,
711+ line: line
712+ )
713+ } catch {
714+ XCTFail ( " Matching for a subtree failed with error: \( error) " , file: file, line: line)
715+ }
716+ }
0 commit comments