Skip to content

Go: struct field tags lose information on parse/print #8452

Description

@timtebeek

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 with ctx.skip(len(tag.Value)) and then returns early when parseStructTagPairs yields 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 from LeadingAnnotations, 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions