Skip to content

Commit

Permalink
go/ssa: test creating package after program has been built
Browse files Browse the repository at this point in the history
  • Loading branch information
xieyuschen committed Sep 16, 2024
1 parent 91d4bdb commit 3b62213
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 0 deletions.
58 changes: 58 additions & 0 deletions go/ssa/instantiate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,66 @@ import (
"testing"

"golang.org/x/tools/go/loader"
"golang.org/x/tools/go/packages"
)

// TestCreateNewPackageAfterBuild tests creating a new package after the program has been built,
// and verifies the slices.Contains has instantiated correctly.
func TestCreateNewPackageAfterBuild(t *testing.T) {

ar := `
-- go.mod --
module example.com
go 1.18
-- main.go --
package p
import "slices"
func main(){
ints := []int{1, 2, 3, 4, 5}
slices.Contains(ints, 1)
}
-- sub/p2.go --
package p2
import "slices"
func Entry(){
numbers := []float32{1, 2, 3, 4, 5}
slices.Contains(numbers, 1)
}
`
pkgs := PackagesFromArchive(t, ar)

var anotherPkg *packages.Package
for i, p := range pkgs {
if p.Name == "p2" {
anotherPkg = p
pkgs = append(pkgs[:i], pkgs[i+1:]...)
}
}
if anotherPkg == nil {
t.Fatal("cannot find package p2 in the loaded packages")
}

mode := InstantiateGenerics
prog := CreateProgram(t, pkgs, mode)
prog.Build()

npkg := prog.CreatePackage(anotherPkg.Types, anotherPkg.Syntax, anotherPkg.TypesInfo, true)
npkg.Build()

var pkgSlices *Package
for _, pkg := range prog.AllPackages() {
if pkg.Pkg.Name() == "slices" {
pkgSlices = pkg
break
}
}

instanceNum := len(allInstances(pkgSlices.Func("Contains")))
if instanceNum != 2 {
t.Errorf("slices.Contains should have 2 instances but got %d", instanceNum)
}
}

// loadProgram creates loader.Program out of p.
func loadProgram(p string) (*loader.Program, error) {
// Parse
Expand Down
79 changes: 79 additions & 0 deletions go/ssa/testhelper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,86 @@

package ssa

import (
"go/ast"
"go/token"
"go/types"
"testing"

"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/testfiles"
"golang.org/x/tools/txtar"
)

// SetNormalizeAnyForTesting is exported here for external tests.
func SetNormalizeAnyForTesting(normalize bool) {
normalizeAnyForTesting = normalize
}

// PackagesFromArchive creates the packages from archive with txtar format.
func PackagesFromArchive(t *testing.T, archive string) []*packages.Package {
ar := txtar.Parse([]byte(archive))

fs, err := txtar.FS(ar)
if err != nil {
t.Fatal(err)
}

dir := testfiles.CopyToTmp(t, fs)
if err != nil {
t.Fatal(err)
}

var baseConfig = &packages.Config{
Mode: packages.NeedSyntax |
packages.NeedTypesInfo |
packages.NeedDeps |
packages.NeedName |
packages.NeedFiles |
packages.NeedImports |
packages.NeedCompiledGoFiles |
packages.NeedTypes,
Dir: dir,
}
pkgs, err := packages.Load(baseConfig, "./...")
if err != nil {
t.Fatal(err)
}
if num := packages.PrintErrors(pkgs); num > 0 {
t.Fatalf("packages contained %d errors", num)
}
return pkgs
}

// CreateProgram creates a program with given initial packages for testing,
// usually the packages are constructed via PackagesFromArchive.
func CreateProgram(t *testing.T, initial []*packages.Package, mode BuilderMode) *Program {
var fset *token.FileSet
if len(initial) > 0 {
fset = initial[0].Fset
}

prog := NewProgram(fset, mode)

isInitial := make(map[*packages.Package]bool, len(initial))
for _, p := range initial {
isInitial[p] = true
}

packages.Visit(initial, nil, func(p *packages.Package) {
if p.Types != nil && !p.IllTyped {
var files []*ast.File
var info *types.Info
if isInitial[p] {
files = p.Syntax
info = p.TypesInfo
}
prog.CreatePackage(p.Types, files, info, true)
return
}

t.Fatalf("package %s or its any dependency contains errors", p.Name)
})

return prog
}

0 comments on commit 3b62213

Please sign in to comment.