SwiftSyntax: how to filter list items out of list syntax?

if i have a MemberDeclListSyntax or AttributeListSyntax, and i am iterating through their list items, how do i modify the list such that some of the elements are conditionally excluded? something like a compactMap operation?

as far as i could tell from browsing API you can only remove list items one at a time which doesn’t mix well with iteration, and this takes an Int index which is different from a SyntaxChildrenIndex so i don’t know what order (forward or reversed) i need to delete the children in.

Does the following work for you?

let list: MemberDeclListSyntax = …
let filteredList = MemberDeclListSyntax(list.filter({ yourCondition($0) }))

it doesn’t compile:

override 
func visit(_ list:MemberDeclListSyntax) -> Syntax
{
    let filteredList:MemberDeclListSyntax = .init(list.filter({ _ in true }))
    return super.visit(filteredList)
}
error: cannot convert value of type '[MemberDeclListSyntax.Element]' (aka 'Array<MemberDeclListItemSyntax>') to expected argument type 'Syntax'
        let filteredList:MemberDeclListSyntax = .init(list.filter({ _ in true }))
                                                           ^
error: value of optional type 'MemberDeclListSyntax?' must be unwrapped to a value of type 'MemberDeclListSyntax'
        let filteredList:MemberDeclListSyntax = .init(list.filter({ _ in true }))
                                                 ^
note: coalesce using '??' to provide a default when the optional value contains 'nil'
        let filteredList:MemberDeclListSyntax = .init(list.filter({ _ in true }))
                                                 ^
                                                                                  ?? <#default value#>
note: force-unwrap using '!' to abort execution if the optional value contains 'nil'
        let filteredList:MemberDeclListSyntax = .init(list.filter({ _ in true }))

more generally, how do you delete things with a SyntaxRewriter? if a MemberDeclListSyntax would become empty, how do i drop the container?

Which version of SwiftSyntax are you using? The following compiles fine for me with current main.


class X: SyntaxRewriter {
  override func visit(_ list:MemberDeclListSyntax) -> Syntax {
      let filteredList:MemberDeclListSyntax = .init(list.filter({ _ in true }))
      return super.visit(filteredList)
  }
}

If you are using the last release of SwiftSyntax, you would need to use SyntaxFactory

class X: SyntaxRewriter {
  override func visit(_ list:MemberDeclListSyntax) -> Syntax {
    let filteredList:MemberDeclListSyntax = SyntaxFactory.makeMemberDeclList(list.filter({ _ in true }))
    return super.visit(filteredList)
  }
}
1 Like
.package(url: "https://github.com/apple/swift-syntax.git", 
    branch: "swift-DEVELOPMENT-SNAPSHOT-2022-08-09-a"),

here is an example project: GitHub - kelvin13/swift-syntax-compile-error-test

i ended up just going the SyntaxFactory route, which worked for my use case.

To be clear: The difference between the SyntaxFactory and non-SyntaxFactory implementation was because we recently deprecated SyntaxFactory in favor of initializers on the Syntax types: Deprecate SyntaxFactory by ahoppen · Pull Request #539 · apple/swift-syntax · GitHub

1 Like

i gotta upgrade my toolchain because i am still on the 8/9/22 one but i’ll check it out!