openrewrite / openrewrite/rewrite
Go: struct field tags lose information on parse/print
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 3.7k
- Forks
- 570
- Avg merge
- 13h 12m
- Merged PRs (30d)
- 261
Description
What version of OpenRewrite are you using?
Current main (27baa806).
What is the smallest, simplest way to reproduce the problem?
Parse and print any Go file containing a struct field tag that isn't in gofmt's canonical key:"value" shape. Each of these fails to round-trip:
| Input field | Printed back as |
|---|---|
Name string "json:\"name\"" (interpreted-string tag) |
Name string — tag gone |
Name string `notakeyvalue` |
Name string — tag gone |
Name string `` (empty tag) |
Name string — tag gone |
Name string `json:"name" garbage` |
Name string `json:"name"` — trailing text gone |
ID int64 ` json:"id" ` |
ID int64 `json:"id"` — inner padding gone |
All five are accepted by the Go compiler, and the first one is read by reflect.StructTag exactly like the backtick form.
What did you expect to see?
Parse/print is lossless for every tag a Go compiler accepts.
What did you see instead?
Silent source corruption: any recipe that edits a file containing such a tag rewrites or deletes the tag as a side effect, in a hunk the recipe never intended to touch.
What is the full stack trace of any errors you encountered?
No error — that's the problem, it's silent.
Root cause
mapStructTag(rewrite-go/pkg/parser/go_parser.go:2985) consumes the literal withctx.skip(len(tag.Value))and then returns early whenparseStructTagPairsyields no pairs, so nothing at all survives in the LST. It also strips the wrapping quotes by hand rather than unquoting, so an interpreted-string tag's escapes are never resolved.parseStructTagPairs(rewrite-go/pkg/parser/go_parser.go:3158) breaks at the first unparseable pair without keeping the remainder.- The printer (
rewrite-go/pkg/printer/go_printer.go:488) rebuilds the tag purely fromLeadingAnnotations, always in backtick form with zero inner padding, so anything the annotations can't express is lost.
org.openrewrite.golang.marker.StructTag already exists for exactly this purpose (and already implements RpcCodec) but is currently unreferenced.
Fix
Under way — the parser attaches the verbatim literal via the existing StructTag marker whenever LeadingAnnotations can't faithfully reproduce it, and the printer prefers that literal but only while it still agrees with the annotations, so recipes that edit annotations still take effect. PR to follow.
Follow-up
Once this is released, the parse/print validation suppressions added downstream in the Go recipe repository to work around this corruption can be removed, and the affected recipes re-validated without them.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read rewrite-go/pkg/parser/go_parser.go around mapStructTag and parseStructTagPairs, then inspect rewrite-go/pkg/printer/go_printer.go around the struct-tag printer and the existing StructTag marker. Reproduce the five parse/print cases, then verify round-tripping preserves their literals while annotation edits still affect output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- compilers, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 30/100