Skip to content

Commit 352e41a

Browse files
committed
internal/gcimporter: updates how imports are handled in unified IR
The imports of the main package are now all of the packages that were referenced during reading the unified IR. This is similar to the non-bundled option for iimport. Without this imports of some packages are not the transitive closure. Fixes golang/go#58296 Change-Id: I4c58c99a5538a9f990ca7325baa1637e7141a97e Reviewed-on: https://go-review.googlesource.com/c/tools/+/465936 Run-TryBot: Tim King <[email protected]> gopls-CI: kokoro <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Alan Donovan <[email protected]>
1 parent 72d72f9 commit 352e41a

File tree

5 files changed

+97
-30
lines changed

5 files changed

+97
-30
lines changed

internal/gcimporter/gcimporter_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"path"
2424
"path/filepath"
2525
"runtime"
26+
"sort"
2627
"strings"
2728
"testing"
2829
"time"
@@ -847,6 +848,60 @@ func TestIssue57729(t *testing.T) {
847848
}
848849
}
849850

851+
func TestIssue58296(t *testing.T) {
852+
// Compiles packages c, b, and a where c imports b and b imports a,
853+
// then imports c with stub *types.Packages for b and a, and checks that
854+
// both a and b are in the Imports() of c.
855+
//
856+
// This is how go/packages can read the exportdata when NeedDeps is off.
857+
858+
// This package only handles gc export data.
859+
needsCompiler(t, "gc")
860+
testenv.NeedsGoBuild(t) // to find stdlib export data in the build cache
861+
862+
// On windows, we have to set the -D option for the compiler to avoid having a drive
863+
// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
864+
if runtime.GOOS == "windows" {
865+
t.Skip("avoid dealing with relative paths/drive letters on windows")
866+
}
867+
868+
tmpdir := mktmpdir(t)
869+
defer os.RemoveAll(tmpdir)
870+
testoutdir := filepath.Join(tmpdir, "testdata")
871+
872+
apkg := filepath.Join(testoutdir, "a")
873+
bpkg := filepath.Join(testoutdir, "b")
874+
cpkg := filepath.Join(testoutdir, "c")
875+
876+
srcdir := filepath.Join("testdata", "issue58296")
877+
compilePkg(t, filepath.Join(srcdir, "a"), "a.go", testoutdir, nil, apkg)
878+
compilePkg(t, filepath.Join(srcdir, "b"), "b.go", testoutdir, map[string]string{apkg: filepath.Join(testoutdir, "a.o")}, bpkg)
879+
compilePkg(t, filepath.Join(srcdir, "c"), "c.go", testoutdir, map[string]string{bpkg: filepath.Join(testoutdir, "b.o")}, cpkg)
880+
881+
// The export data reader for c cannot rely on Package.Imports
882+
// being populated for a or b. (For the imports {a,b} it is unset.)
883+
imports := map[string]*types.Package{
884+
apkg: types.NewPackage(apkg, "a"),
885+
bpkg: types.NewPackage(bpkg, "b"),
886+
}
887+
888+
// make sure a and b are both imported by c.
889+
pkg, err := Import(imports, "./c", testoutdir, nil)
890+
if err != nil {
891+
t.Fatal(err)
892+
}
893+
894+
var names []string
895+
for _, imp := range pkg.Imports() {
896+
names = append(names, imp.Name())
897+
}
898+
sort.Strings(names)
899+
900+
if got, want := strings.Join(names, ","), "a,b"; got != want {
901+
t.Errorf("got imports %v for package c. wanted %v", names, want)
902+
}
903+
}
904+
850905
// apkg returns the package "a" prefixed by (as a package) testoutdir
851906
func apkg(testoutdir string) string {
852907
apkg := testoutdir + "/a"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package a
6+
7+
type A int
8+
9+
func (A) f() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package b
6+
7+
import "./a"
8+
9+
type B struct {
10+
a a.A
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package c
6+
7+
import "./b"
8+
9+
type C struct {
10+
b b.B
11+
}

internal/gcimporter/ureader_yes.go

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package gcimporter
1212
import (
1313
"go/token"
1414
"go/types"
15+
"sort"
1516
"strings"
1617

1718
"golang.org/x/tools/internal/pkgbits"
@@ -121,6 +122,16 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st
121122
iface.Complete()
122123
}
123124

125+
// Imports() of pkg are all of the transitive packages that were loaded.
126+
var imps []*types.Package
127+
for _, imp := range pr.pkgs {
128+
if imp != nil && imp != pkg {
129+
imps = append(imps, imp)
130+
}
131+
}
132+
sort.Sort(byPath(imps))
133+
pkg.SetImports(imps)
134+
124135
pkg.MarkComplete()
125136
return pkg
126137
}
@@ -260,39 +271,9 @@ func (r *reader) doPkg() *types.Package {
260271
pkg := types.NewPackage(path, name)
261272
r.p.imports[path] = pkg
262273

263-
imports := make([]*types.Package, r.Len())
264-
for i := range imports {
265-
imports[i] = r.pkg()
266-
}
267-
pkg.SetImports(flattenImports(imports))
268-
269274
return pkg
270275
}
271276

272-
// flattenImports returns the transitive closure of all imported
273-
// packages rooted from pkgs.
274-
func flattenImports(pkgs []*types.Package) []*types.Package {
275-
var res []*types.Package
276-
seen := make(map[*types.Package]struct{})
277-
for _, pkg := range pkgs {
278-
if _, ok := seen[pkg]; ok {
279-
continue
280-
}
281-
seen[pkg] = struct{}{}
282-
res = append(res, pkg)
283-
284-
// pkg.Imports() is already flattened.
285-
for _, pkg := range pkg.Imports() {
286-
if _, ok := seen[pkg]; ok {
287-
continue
288-
}
289-
seen[pkg] = struct{}{}
290-
res = append(res, pkg)
291-
}
292-
}
293-
return res
294-
}
295-
296277
// @@@ Types
297278

298279
func (r *reader) typ() types.Type {

0 commit comments

Comments
 (0)