go/{analysis,packages}: add TypesSizes
Many Analyzers need to measure the width of an integer and all today use hacks. This change causes analysis.Pass to retain and expose the type sizing function used during type checking. This in turn requires go/packages to retain and expose the type sizing function in Packages.TypesSizes, which addresses a longstanding need among many of its clients. Change-Id: Ia8362019bcde34c10cb4fbc38cfdfddcbef3eb5c Reviewed-on: https://go-review.googlesource.com/c/158317 Reviewed-by: Michael Matloob <matloob@golang.org> Run-TryBot: Michael Matloob <matloob@golang.org>
This commit is contained in:
parent
b258f6da23
commit
b4b6fe2cb8
|
@ -87,6 +87,7 @@ type Pass struct {
|
||||||
OtherFiles []string // names of non-Go files of this package
|
OtherFiles []string // names of non-Go files of this package
|
||||||
Pkg *types.Package // type information about the package
|
Pkg *types.Package // type information about the package
|
||||||
TypesInfo *types.Info // type information about the syntax trees
|
TypesInfo *types.Info // type information about the syntax trees
|
||||||
|
TypesSizes types.Sizes // function for computing sizes of types
|
||||||
|
|
||||||
// Report reports a Diagnostic, a finding about a specific location
|
// Report reports a Diagnostic, a finding about a specific location
|
||||||
// in the analyzed source code such as a potential mistake.
|
// in the analyzed source code such as a potential mistake.
|
||||||
|
|
|
@ -492,6 +492,7 @@ func (act *action) execOnce() {
|
||||||
OtherFiles: act.pkg.OtherFiles,
|
OtherFiles: act.pkg.OtherFiles,
|
||||||
Pkg: act.pkg.Types,
|
Pkg: act.pkg.Types,
|
||||||
TypesInfo: act.pkg.TypesInfo,
|
TypesInfo: act.pkg.TypesInfo,
|
||||||
|
TypesSizes: act.pkg.TypesSizes,
|
||||||
ResultOf: inputs,
|
ResultOf: inputs,
|
||||||
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
|
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
|
||||||
ImportObjectFact: act.importObjectFact,
|
ImportObjectFact: act.importObjectFact,
|
||||||
|
|
|
@ -114,7 +114,8 @@ func init() {
|
||||||
// library we cannot assume types.SizesFor is consistent with arches.
|
// library we cannot assume types.SizesFor is consistent with arches.
|
||||||
// For now, assume 64-bit norms and print a warning.
|
// For now, assume 64-bit norms and print a warning.
|
||||||
// But this warning should really be deferred until we attempt to use
|
// But this warning should really be deferred until we attempt to use
|
||||||
// arch, which is very unlikely.
|
// arch, which is very unlikely. Better would be
|
||||||
|
// to defer size computation until we have Pass.TypesSizes.
|
||||||
arch.sizes = types.SizesFor("gc", "amd64")
|
arch.sizes = types.SizesFor("gc", "amd64")
|
||||||
log.Printf("unknown architecture %s", arch.name)
|
log.Printf("unknown architecture %s", arch.name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ package cgocall
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/build"
|
|
||||||
"go/format"
|
"go/format"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
@ -45,7 +44,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
|
||||||
return nil, nil // doesn't use cgo
|
return nil, nil // doesn't use cgo
|
||||||
}
|
}
|
||||||
|
|
||||||
cgofiles, info, err := typeCheckCgoSourceFiles(pass.Fset, pass.Pkg, pass.Files, pass.TypesInfo)
|
cgofiles, info, err := typeCheckCgoSourceFiles(pass.Fset, pass.Pkg, pass.Files, pass.TypesInfo, pass.TypesSizes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -171,7 +170,7 @@ func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(t
|
||||||
// limited ourselves here to preserving function bodies and initializer
|
// limited ourselves here to preserving function bodies and initializer
|
||||||
// expressions since that is all that the cgocall analyzer needs.
|
// expressions since that is all that the cgocall analyzer needs.
|
||||||
//
|
//
|
||||||
func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*ast.File, info *types.Info) ([]*ast.File, *types.Info, error) {
|
func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*ast.File, info *types.Info, sizes types.Sizes) ([]*ast.File, *types.Info, error) {
|
||||||
const thispkg = "·this·"
|
const thispkg = "·this·"
|
||||||
|
|
||||||
// Which files are cgo files?
|
// Which files are cgo files?
|
||||||
|
@ -269,8 +268,7 @@ func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*a
|
||||||
Importer: importerFunc(func(path string) (*types.Package, error) {
|
Importer: importerFunc(func(path string) (*types.Package, error) {
|
||||||
return importMap[path], nil
|
return importMap[path], nil
|
||||||
}),
|
}),
|
||||||
// TODO(adonovan): Sizes should probably be provided by analysis.Pass.
|
Sizes: sizes,
|
||||||
Sizes: types.SizesFor("gc", build.Default.GOARCH),
|
|
||||||
Error: func(error) {}, // ignore errors (e.g. unused import)
|
Error: func(error) {}, // ignore errors (e.g. unused import)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package printf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/build"
|
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"golang.org/x/tools/go/analysis"
|
"golang.org/x/tools/go/analysis"
|
||||||
|
@ -235,5 +234,3 @@ func matchStructArgType(pass *analysis.Pass, t printfArgType, typ *types.Struct,
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
var archSizes = types.SizesFor("gc", build.Default.GOARCH)
|
|
||||||
|
|
|
@ -12,10 +12,8 @@ package shift
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/build"
|
|
||||||
"go/constant"
|
"go/constant"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/analysis"
|
"golang.org/x/tools/go/analysis"
|
||||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||||
|
@ -93,36 +91,9 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b, ok := t.Underlying().(*types.Basic)
|
size := 8 * pass.TypesSizes.Sizeof(t)
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var size int64
|
|
||||||
switch b.Kind() {
|
|
||||||
case types.Uint8, types.Int8:
|
|
||||||
size = 8
|
|
||||||
case types.Uint16, types.Int16:
|
|
||||||
size = 16
|
|
||||||
case types.Uint32, types.Int32:
|
|
||||||
size = 32
|
|
||||||
case types.Uint64, types.Int64:
|
|
||||||
size = 64
|
|
||||||
case types.Int, types.Uint:
|
|
||||||
size = uintBitSize
|
|
||||||
case types.Uintptr:
|
|
||||||
size = uintptrBitSize
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if amt >= size {
|
if amt >= size {
|
||||||
ident := analysisutil.Format(pass.Fset, x)
|
ident := analysisutil.Format(pass.Fset, x)
|
||||||
pass.Reportf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
|
pass.Reportf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
uintBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uint])
|
|
||||||
uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr])
|
|
||||||
)
|
|
||||||
|
|
||||||
var archSizes = types.SizesFor("gc", build.Default.GOARCH)
|
|
||||||
|
|
|
@ -329,6 +329,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
|
||||||
OtherFiles: cfg.NonGoFiles,
|
OtherFiles: cfg.NonGoFiles,
|
||||||
Pkg: pkg,
|
Pkg: pkg,
|
||||||
TypesInfo: info,
|
TypesInfo: info,
|
||||||
|
TypesSizes: tc.Sizes,
|
||||||
ResultOf: inputs,
|
ResultOf: inputs,
|
||||||
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
|
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
|
||||||
ImportObjectFact: facts.ImportObjectFact,
|
ImportObjectFact: facts.ImportObjectFact,
|
||||||
|
|
|
@ -250,6 +250,9 @@ type Package struct {
|
||||||
// TypesInfo provides type information about the package's syntax trees.
|
// TypesInfo provides type information about the package's syntax trees.
|
||||||
// It is set only when Syntax is set.
|
// It is set only when Syntax is set.
|
||||||
TypesInfo *types.Info
|
TypesInfo *types.Info
|
||||||
|
|
||||||
|
// TypesSizes provides the effective size function for types in TypesInfo.
|
||||||
|
TypesSizes types.Sizes
|
||||||
}
|
}
|
||||||
|
|
||||||
// An Error describes a problem with a package's metadata, syntax, or types.
|
// An Error describes a problem with a package's metadata, syntax, or types.
|
||||||
|
@ -582,6 +585,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
|
||||||
lpkg.Fset = ld.Fset
|
lpkg.Fset = ld.Fset
|
||||||
lpkg.Syntax = []*ast.File{}
|
lpkg.Syntax = []*ast.File{}
|
||||||
lpkg.TypesInfo = new(types.Info)
|
lpkg.TypesInfo = new(types.Info)
|
||||||
|
lpkg.TypesSizes = ld.sizes
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,6 +673,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
|
||||||
Scopes: make(map[ast.Node]*types.Scope),
|
Scopes: make(map[ast.Node]*types.Scope),
|
||||||
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||||
}
|
}
|
||||||
|
lpkg.TypesSizes = ld.sizes
|
||||||
|
|
||||||
importer := importerFunc(func(path string) (*types.Package, error) {
|
importer := importerFunc(func(path string) (*types.Package, error) {
|
||||||
if path == "unsafe" {
|
if path == "unsafe" {
|
||||||
|
|
Loading…
Reference in New Issue