[JuliaSyntax] Return generator from `attrnames(::SyntaxTree)` (#61522)
Return a generator instead of a `Vector{Symbol}` from `attrnames` to
avoid unnecessary allocation. `attrnames` is called from
`hasproperty(::SyntaxTree, ::Symbol)` and similar hot-path queries, so
avoiding the allocation would be worthwhile. This is compatible with the
`propertynames` interface which accepts any iterable of properties,
although `node_string` needed to be updated since the return value is
now `Tuple{Vararg{Symbol}}` instead of a vector of the symbols.
Also wrap inference tests in a `@testset` and add a test for
`hasproperty` return type inference.
Follows up JuliaLang/julia#61518.