cmd/go/internal/list: make a copy of the package before zeroing fields

go list -json=<fields> zeroes out the fields in the package struct
that aren't specified. The problem with this is that some of the fields
have references into other fields: specifically, the NoGoError's
Error() function accesses the package struct's Dir field, so if we
clear it out the error will just print out "no Go files in" without a
directory. Instead, make a copy of the package struct before we zero
out the fields so the original values are still there.

For #64946

Change-Id: I95103e91fa0782bb23a86a965d5eb87cb12654c6
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest
Reviewed-on: https://go-review.googlesource.com/c/go/+/553795
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
This commit is contained in:
Michael Matloob 2024-01-03 14:23:49 -05:00
parent e076c1b897
commit a64d5be912
2 changed files with 14 additions and 2 deletions

View File

@ -449,13 +449,15 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
if listJson {
do = func(x any) {
if !listJsonFields.needAll() {
v := reflect.ValueOf(x).Elem() // do is always called with a non-nil pointer.
// Clear all non-requested fields.
// Set x to a copy of itself with all non-requested fields cleared.
v := reflect.New(reflect.TypeOf(x).Elem()).Elem() // do is always called with a non-nil pointer.
v.Set(reflect.ValueOf(x).Elem())
for i := 0; i < v.NumField(); i++ {
if !listJsonFields.needAny(v.Type().Field(i).Name) {
v.Field(i).SetZero()
}
}
x = v.Interface()
}
b, err := json.MarshalIndent(x, "", "\t")
if err != nil {

View File

@ -0,0 +1,10 @@
cd mod
go list -e -json=ImportPath,Error ./foo
stdout '"Err": "no Go files in .*(/|\\\\)src(/|\\\\)mod(/|\\\\)foo"'
-- mod/go.mod --
module example.com/foo
go 1.21
-- mod/foo/README.md --
empty