diff --git a/go/packages/golist.go b/go/packages/golist.go index 2675c882..2dcc85e2 100644 --- a/go/packages/golist.go +++ b/go/packages/golist.go @@ -13,6 +13,7 @@ import ( "os" "os/exec" "path/filepath" + "reflect" "regexp" "strings" "sync" @@ -488,6 +489,7 @@ func golistDriverCurrent(cfg *Config, words ...string) (*driverResponse, error) if err != nil { return nil, err } + seen := make(map[string]*jsonPackage) // Decode the JSON and convert it to Package form. var response driverResponse for dec := json.NewDecoder(buf); dec.More(); { @@ -510,6 +512,15 @@ func golistDriverCurrent(cfg *Config, words ...string) (*driverResponse, error) return nil, fmt.Errorf("package missing import path: %+v", p) } + if old, found := seen[p.ImportPath]; found { + if !reflect.DeepEqual(p, old) { + return nil, fmt.Errorf("go list repeated package %v with different values", p.ImportPath) + } + // skip the duplicate + continue + } + seen[p.ImportPath] = p + pkg := &Package{ Name: p.Name, ID: p.ImportPath, diff --git a/go/packages/packages.go b/go/packages/packages.go index 4e78f341..f3e04f39 100644 --- a/go/packages/packages.go +++ b/go/packages/packages.go @@ -437,6 +437,11 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { lpkg.initial = true } } + for i, root := range roots { + if initial[i] == nil { + return nil, fmt.Errorf("root package %v is missing", root) + } + } // Materialize the import graph. diff --git a/go/packages/packages_test.go b/go/packages/packages_test.go index 3f800036..275e8899 100644 --- a/go/packages/packages_test.go +++ b/go/packages/packages_test.go @@ -1488,6 +1488,31 @@ EOF } } +// This test that a simple x test package layout loads correctly. +// There was a bug in go list where it returned multiple copies of the same +// package (specifically in this case of golang.org/fake/a), and this triggered +// a bug in go/packages where it would leave an empty entry in the root package +// list. This would then cause a nil pointer crash. +// This bug was triggered by the simple package layout below, and thus this +// test will make sure the bug remains fixed. +func TestBasicXTest(t *testing.T) { packagestest.TestAll(t, testBasicXTest) } +func testBasicXTest(t *testing.T, exporter packagestest.Exporter) { + exported := packagestest.Export(t, exporter, []packagestest.Module{{ + Name: "golang.org/fake", + Files: map[string]interface{}{ + "a/a.go": `package a;`, + "a/a_test.go": `package a_test;`, + }}}) + defer exported.Cleanup() + + exported.Config.Mode = packages.LoadFiles + exported.Config.Tests = true + _, err := packages.Load(exported.Config, "golang.org/fake/a") + if err != nil { + t.Fatal(err) + } +} + func errorMessages(errors []packages.Error) []string { var msgs []string for _, err := range errors {