mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
go/ssa/ssautil: add AllPackages method
In go1.10, go/packages falls back to loading all packages from source but not typechecking function bodies for imports. The ssautil.Packages function would nonetheless provide the partially-typed ASTs to the SSA builder, which would crash. Now Packages only passes syntax trees to the SSA builder for the initial packages, which are the only ones guaranteed to be fully typed. It is impossible to discern whether the caller of Packages intends to build SSA code for dependencies, as in some clients such as cmd/callgraph, so we add a new function, AllPackages, that expresses this intent. Fixes golang/go#28106 Change-Id: I6a88b7c7545e9de90b61f5bee0e6de3d2e21b548 Reviewed-on: https://go-review.googlesource.com/c/141686 Reviewed-by: Michael Matloob <matloob@golang.org> Run-TryBot: Michael Matloob <matloob@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
4b6ee5fb87
commit
aa46a01996
@ -187,7 +187,7 @@ func doCallgraph(dir, gopath, algo, format string, tests bool, args []string) er
|
||||
}
|
||||
|
||||
// Create and build SSA-form program representation.
|
||||
prog, pkgs := ssautil.Packages(initial, 0)
|
||||
prog, pkgs := ssautil.AllPackages(initial, 0)
|
||||
prog.Build()
|
||||
|
||||
// -- call graph construction ------------------------------------------
|
||||
|
@ -131,7 +131,7 @@ func doMain() error {
|
||||
}
|
||||
|
||||
// Create SSA-form program representation.
|
||||
prog, pkgs := ssautil.Packages(initial, mode)
|
||||
prog, pkgs := ssautil.AllPackages(initial, mode)
|
||||
|
||||
for i, p := range pkgs {
|
||||
if p == nil {
|
||||
|
@ -155,8 +155,8 @@ func ExampleLoadWholeProgram() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Create SSA packages for all well-typed packages.
|
||||
prog, pkgs := ssautil.Packages(initial, ssa.PrintPackages)
|
||||
// Create SSA packages for well-typed packages and their dependencies.
|
||||
prog, pkgs := ssautil.AllPackages(initial, ssa.PrintPackages)
|
||||
_ = pkgs
|
||||
|
||||
// Build SSA code for the whole program.
|
||||
|
@ -16,19 +16,52 @@ import (
|
||||
"golang.org/x/tools/go/ssa"
|
||||
)
|
||||
|
||||
// Packages creates an SSA program for a set of packages loaded from
|
||||
// source syntax using the golang.org/x/tools/go/packages.Load function.
|
||||
// It creates and returns an SSA package for each well-typed package in
|
||||
// the initial list. The resulting list of packages has the same length
|
||||
// as initial, and contains a nil if SSA could not be constructed for
|
||||
// the corresponding initial package.
|
||||
// Packages creates an SSA program for a set of packages.
|
||||
//
|
||||
// Code for bodies of functions is not built until Build is called
|
||||
// on the resulting Program.
|
||||
// The packages must have been loaded from source syntax using the
|
||||
// golang.org/x/tools/go/packages.Load function in LoadSyntax or
|
||||
// LoadAllSyntax mode.
|
||||
//
|
||||
// Packages creates an SSA package for each well-typed package in the
|
||||
// initial list, plus all their dependencies. The resulting list of
|
||||
// packages corresponds to the list of initial packages, and may contain
|
||||
// a nil if SSA code could not be constructed for the corresponding initial
|
||||
// package due to type errors.
|
||||
//
|
||||
// Code for bodies of functions is not built until Build is called on
|
||||
// the resulting Program. SSA code is constructed only for the initial
|
||||
// packages with well-typed syntax trees.
|
||||
//
|
||||
// The mode parameter controls diagnostics and checking during SSA construction.
|
||||
//
|
||||
func Packages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, []*ssa.Package) {
|
||||
return doPackages(initial, mode, false)
|
||||
}
|
||||
|
||||
// AllPackages creates an SSA program for a set of packages plus all
|
||||
// their dependencies.
|
||||
//
|
||||
// The packages must have been loaded from source syntax using the
|
||||
// golang.org/x/tools/go/packages.Load function in LoadAllSyntax mode.
|
||||
//
|
||||
// AllPackages creates an SSA package for each well-typed package in the
|
||||
// initial list, plus all their dependencies. The resulting list of
|
||||
// packages corresponds to the list of intial packages, and may contain
|
||||
// a nil if SSA code could not be constructed for the corresponding
|
||||
// initial package due to type errors.
|
||||
//
|
||||
// Code for bodies of functions is not built until Build is called on
|
||||
// the resulting Program. SSA code is constructed for all packages with
|
||||
// well-typed syntax trees.
|
||||
//
|
||||
// The mode parameter controls diagnostics and checking during SSA construction.
|
||||
//
|
||||
func AllPackages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, []*ssa.Package) {
|
||||
return doPackages(initial, mode, true)
|
||||
}
|
||||
|
||||
func doPackages(initial []*packages.Package, mode ssa.BuilderMode, deps bool) (*ssa.Program, []*ssa.Package) {
|
||||
|
||||
var fset *token.FileSet
|
||||
if len(initial) > 0 {
|
||||
fset = initial[0].Fset
|
||||
@ -36,10 +69,19 @@ func Packages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program,
|
||||
|
||||
prog := ssa.NewProgram(fset, mode)
|
||||
|
||||
isInitial := make(map[*packages.Package]bool, len(initial))
|
||||
for _, p := range initial {
|
||||
isInitial[p] = true
|
||||
}
|
||||
|
||||
ssamap := make(map[*packages.Package]*ssa.Package)
|
||||
packages.Visit(initial, nil, func(p *packages.Package) {
|
||||
if p.Types != nil && !p.IllTyped {
|
||||
ssamap[p] = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
|
||||
var files []*ast.File
|
||||
if deps || isInitial[p] {
|
||||
files = p.Syntax
|
||||
}
|
||||
ssamap[p] = prog.CreatePackage(p.Types, files, p.TypesInfo, true)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -104,3 +104,17 @@ func TestBuildPackage_MissingImport(t *testing.T) {
|
||||
t.Fatal("BuildPackage succeeded unexpectedly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue28106(t *testing.T) {
|
||||
// In go1.10, go/packages loads all packages from source, not
|
||||
// export data, but does not type check function bodies of
|
||||
// imported packages. This test ensures that we do not attempt
|
||||
// to run the SSA builder on functions without type information.
|
||||
cfg := &packages.Config{Mode: packages.LoadSyntax}
|
||||
pkgs, err := packages.Load(cfg, "runtime")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
prog, _ := ssautil.Packages(pkgs, 0)
|
||||
prog.Build() // no crash
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user