mirror of
https://github.com/golang/go
synced 2024-11-18 16:54:43 -07:00
go.tools/cmd/vet: use types.Eval to simplify some checking.
Depends on CL 10748044 R=gri CC=golang-dev https://golang.org/cl/11206043
This commit is contained in:
parent
a3301d1bc6
commit
b042505490
4
cmd/vet/testdata/print.go
vendored
4
cmd/vet/testdata/print.go
vendored
@ -75,8 +75,8 @@ func PrintfTests() {
|
|||||||
fmt.Printf("%x %x %x %x", 3, i, "hi", s)
|
fmt.Printf("%x %x %x %x", 3, i, "hi", s)
|
||||||
fmt.Printf("%X %X %X %X", 3, i, "hi", s)
|
fmt.Printf("%X %X %X %X", 3, i, "hi", s)
|
||||||
fmt.Printf("%.*s %d %g", 3, "hi", 23, 2.3)
|
fmt.Printf("%.*s %d %g", 3, "hi", 23, 2.3)
|
||||||
fmt.Printf("%s", stringerv)
|
fmt.Printf("%s", &stringerv)
|
||||||
fmt.Printf("%T", stringerv)
|
fmt.Printf("%T", &stringerv)
|
||||||
fmt.Printf("%*%", 2) // Ridiculous but allowed.
|
fmt.Printf("%*%", 2) // Ridiculous but allowed.
|
||||||
// Some bad format/argTypes
|
// Some bad format/argTypes
|
||||||
fmt.Printf("%b", "hi") // ERROR "arg .hi. for printf verb %b of wrong type"
|
fmt.Printf("%b", "hi") // ERROR "arg .hi. for printf verb %b of wrong type"
|
||||||
|
@ -63,31 +63,21 @@ func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
stringerMethodType = types.New("func() string")
|
||||||
|
errorType = types.New("interface{ Error() string }")
|
||||||
|
stringerType = types.New("interface{ String() string }")
|
||||||
|
)
|
||||||
|
|
||||||
func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool {
|
func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool {
|
||||||
// TODO: for now, we can only test builtin types, untyped constants, and Stringer/Errors.
|
// TODO: for now, we can only test builtin types, untyped constants, and Stringer/Errors.
|
||||||
typ := f.pkg.types[arg]
|
typ := f.pkg.types[arg]
|
||||||
if typ == nil {
|
if typ == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// If we can use a string and this is a named type, does it implement the Stringer or Error interface?
|
// If we can use a string, does arg implement the Stringer or Error interface?
|
||||||
// TODO: Simplify when we have the IsAssignableTo predicate in go/types.
|
if t&argString != 0 {
|
||||||
if named, ok := typ.(*types.Named); ok && t&argString != 0 {
|
if types.IsAssignableTo(typ, errorType) || types.IsAssignableTo(typ, stringerType) {
|
||||||
for i := 0; i < named.NumMethods(); i++ {
|
|
||||||
method := named.Method(i)
|
|
||||||
// Method must be either String or Error.
|
|
||||||
if method.Name() != "String" && method.Name() != "Error" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sig := method.Type().(*types.Signature)
|
|
||||||
// There must be zero arguments and one return.
|
|
||||||
if sig.Params().Len() != 0 || sig.Results().Len() != 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Result must be string.
|
|
||||||
if !isUniverseString(sig.Results().At(0).Type()) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// It's a Stringer and we can print it.
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,6 +146,12 @@ func (f *File) numArgsInSignature(call *ast.CallExpr) int {
|
|||||||
// func Error() string
|
// func Error() string
|
||||||
// where "string" is the universe's string type. We know the method is called "Error".
|
// where "string" is the universe's string type. We know the method is called "Error".
|
||||||
func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
|
func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
|
||||||
|
typ := f.pkg.types[call]
|
||||||
|
if typ != nil {
|
||||||
|
// We know it's called "Error", so just check the function signature.
|
||||||
|
return types.IsIdentical(f.pkg.types[call.Fun], stringerMethodType)
|
||||||
|
}
|
||||||
|
// Without types, we can still check by hand.
|
||||||
// Is it a selector expression? Otherwise it's a function call, not a method call.
|
// Is it a selector expression? Otherwise it's a function call, not a method call.
|
||||||
sel, ok := call.Fun.(*ast.SelectorExpr)
|
sel, ok := call.Fun.(*ast.SelectorExpr)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -166,7 +162,7 @@ func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Check the type of the method declaration
|
// Check the type of the method declaration
|
||||||
typ := f.pkg.types[sel]
|
typ = f.pkg.types[sel]
|
||||||
if typ == nil {
|
if typ == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user