The question of whether an identifier needs escaping can’t be answered generically. For example, as is perfectly valid as a member lookup type.as but not as a variable declaration let as = 1. init, on the other hand, also needs to be escaped for member access.
Depending on your use case, I would suggest parsing a little code snippet with your intended identifier name and checking if that produces no error. For example,
let myVariableName = "as"
var parser = Parser("var \(myVariableName)")
let decl = DeclSyntax.parse(from: &parser)
return decl.hasError
Or if you want to be extra careful and check that the parser did indeed parse the name as an identifier (this would be more interesting for the foo.init case if you want to make sure that you indeed escape init as a member name, which would parse fine as a keyword access as well).
if case .identifier = decl.as(VariableDeclSyntax.self)?.bindings.first?.pattern.as(IdentifierPatternSyntax.self)?.identifier.tokenKind {
return true
} else {
return false
}
I agree that SwiftSyntax should be able to handle this with types, but it is also never wrong to use backticks in positions where you definitely want an identifier. Backticks on normal identifier-strings are needless but also harmless. (As long as your input doesn’t already have backticks.)
and then the macro implementation could just vacuum up the enum case identifiers, which are already known to be valid identifiers. but an extension macro cannot itself be applied to an extension block.
i guess the next best thing would be to place AvailableCases in the main declaration.