Skip to content

Commit a354ccf

Browse files
committed
go/ssa: test creating package after program has been built
1 parent 91d4bdb commit a354ccf

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

go/ssa/instantiate_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,65 @@ import (
1616
"testing"
1717

1818
"golang.org/x/tools/go/loader"
19+
"golang.org/x/tools/go/packages"
1920
)
2021

22+
// TestCreateNewPackageAfterBuild tests creating a new package after the program has been built,
23+
// and verifies the slices.Contains has instantiated correctly.
24+
func TestCreateNewPackageAfterBuild(t *testing.T) {
25+
ar := `
26+
-- go.mod --
27+
module example.com
28+
go 1.18
29+
-- main.go --
30+
package p
31+
import "slices"
32+
func main(){
33+
ints := []int{1, 2, 3, 4, 5}
34+
slices.Contains(ints, 1)
35+
}
36+
-- sub/p2.go --
37+
package p2
38+
import "slices"
39+
func Entry(){
40+
numbers := []float32{1, 2, 3, 4, 5}
41+
slices.Contains(numbers, 1)
42+
}
43+
`
44+
pkgs := PackagesFromArchive(t, ar)
45+
46+
var anotherPkg *packages.Package
47+
for i, p := range pkgs {
48+
if p.Name == "p2" {
49+
anotherPkg = p
50+
pkgs = append(pkgs[:i], pkgs[i+1:]...)
51+
}
52+
}
53+
if anotherPkg == nil {
54+
t.Fatal("cannot find package p2 in the loaded packages")
55+
}
56+
57+
mode := InstantiateGenerics
58+
prog := CreateProgram(t, pkgs, mode)
59+
prog.Build()
60+
61+
npkg := prog.CreatePackage(anotherPkg.Types, anotherPkg.Syntax, anotherPkg.TypesInfo, true)
62+
npkg.Build()
63+
64+
var pkgSlices *Package
65+
for _, pkg := range prog.AllPackages() {
66+
if pkg.Pkg.Name() == "slices" {
67+
pkgSlices = pkg
68+
break
69+
}
70+
}
71+
72+
instanceNum := len(allInstances(pkgSlices.Func("Contains")))
73+
if instanceNum != 2 {
74+
t.Errorf("slices.Contains should have 2 instances but got %d", instanceNum)
75+
}
76+
}
77+
2178
// loadProgram creates loader.Program out of p.
2279
func loadProgram(p string) (*loader.Program, error) {
2380
// Parse

go/ssa/testhelper_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,86 @@
44

55
package ssa
66

7+
import (
8+
"go/ast"
9+
"go/token"
10+
"go/types"
11+
"testing"
12+
13+
"golang.org/x/tools/go/packages"
14+
"golang.org/x/tools/internal/testfiles"
15+
"golang.org/x/tools/txtar"
16+
)
17+
718
// SetNormalizeAnyForTesting is exported here for external tests.
819
func SetNormalizeAnyForTesting(normalize bool) {
920
normalizeAnyForTesting = normalize
1021
}
22+
23+
// PackagesFromArchive creates the packages from archive with txtar format.
24+
func PackagesFromArchive(t *testing.T, archive string) []*packages.Package {
25+
ar := txtar.Parse([]byte(archive))
26+
27+
fs, err := txtar.FS(ar)
28+
if err != nil {
29+
t.Fatal(err)
30+
}
31+
32+
dir := testfiles.CopyToTmp(t, fs)
33+
if err != nil {
34+
t.Fatal(err)
35+
}
36+
37+
var baseConfig = &packages.Config{
38+
Mode: packages.NeedSyntax |
39+
packages.NeedTypesInfo |
40+
packages.NeedDeps |
41+
packages.NeedName |
42+
packages.NeedFiles |
43+
packages.NeedImports |
44+
packages.NeedCompiledGoFiles |
45+
packages.NeedTypes,
46+
Dir: dir,
47+
}
48+
pkgs, err := packages.Load(baseConfig, "./...")
49+
if err != nil {
50+
t.Fatal(err)
51+
}
52+
if num := packages.PrintErrors(pkgs); num > 0 {
53+
t.Fatalf("packages contained %d errors", num)
54+
}
55+
return pkgs
56+
}
57+
58+
// CreateProgram creates a program with given initial packages for testing,
59+
// usually the packages are constructed via PackagesFromArchive.
60+
func CreateProgram(t *testing.T, initial []*packages.Package, mode BuilderMode) *Program {
61+
var fset *token.FileSet
62+
if len(initial) > 0 {
63+
fset = initial[0].Fset
64+
}
65+
66+
prog := NewProgram(fset, mode)
67+
68+
isInitial := make(map[*packages.Package]bool, len(initial))
69+
for _, p := range initial {
70+
isInitial[p] = true
71+
}
72+
73+
packages.Visit(initial, nil, func(p *packages.Package) {
74+
if p.Types != nil && !p.IllTyped {
75+
var files []*ast.File
76+
var info *types.Info
77+
if isInitial[p] {
78+
files = p.Syntax
79+
info = p.TypesInfo
80+
}
81+
prog.CreatePackage(p.Types, files, info, true)
82+
return
83+
}
84+
85+
t.Fatalf("package %s or its any dependency contains errors", p.Name)
86+
})
87+
88+
return prog
89+
}

0 commit comments

Comments
 (0)