Commit d2825329 authored by Rob Pike's avatar Rob Pike

vet: improve flag handling

Simplify the internal logic for flags controlling what to vet,
by introducing a map of flags that gathers them all together.
This change should simplify the process of adding further flags.

Add a test for untagged struct literals.
Delete a redundant test that was also in the wrong file.
Clean up some ERROR patterns that weren't working.

"make test" passes again.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7305075
parent 6c119a9e
......@@ -13,7 +13,7 @@ import (
// checkAtomicAssignment walks the assignment statement checking for comomon
// mistaken usage of atomic package, such as: x = atomic.AddUint64(&x, 1)
func (f *File) checkAtomicAssignment(n *ast.AssignStmt) {
if !*vetAtomic && !*vetAll {
if !vet("atomic") {
return
}
......
......@@ -25,7 +25,7 @@ var (
// checkBuildTag checks that build tags are in the correct location and well-formed.
func checkBuildTag(name string, data []byte) {
if !*vetBuildTags && !*vetAll {
if !vet("buildtags") {
return
}
lines := bytes.SplitAfter(data, nl)
......
......@@ -25,18 +25,23 @@ import (
var verbose = flag.Bool("v", false, "verbose")
var exitCode = 0
// Flags to control which checks to perform.
// NOTE: Add new flags to the if statement at the top of func main too.
var (
vetAll = flag.Bool("all", true, "check everything; disabled if any explicit check is requested")
vetAtomic = flag.Bool("atomic", false, "check for common mistaken usages of the sync/atomic package")
vetBuildTags = flag.Bool("buildtags", false, "check that +build tags are valid")
vetMethods = flag.Bool("methods", false, "check that canonically named methods are canonically defined")
vetPrintf = flag.Bool("printf", false, "check printf-like invocations")
vetStructTags = flag.Bool("structtags", false, "check that struct field tags have canonical format")
vetRangeLoops = flag.Bool("rangeloops", false, "check that range loop variables are used correctly")
vetUntaggedLiteral = flag.Bool("composites", false, "check that composite literals used type-tagged elements")
)
// Flags to control which checks to perform. "all" is set to true here, and disabled later if
// a flag is set explicitly.
var report = map[string]*bool{
"all": flag.Bool("all", true, "check everything; disabled if any explicit check is requested"),
"atomic": flag.Bool("atomic", false, "check for common mistaken usages of the sync/atomic package"),
"buildtags": flag.Bool("buildtags", false, "check that +build tags are valid"),
"composites": flag.Bool("composites", false, "check that composite literals used type-tagged elements"),
"methods": flag.Bool("methods", false, "check that canonically named methods are canonically defined"),
"printf": flag.Bool("printf", false, "check printf-like invocations"),
"structtags": flag.Bool("structtags", false, "check that struct field tags have canonical format"),
"rangeloops": flag.Bool("rangeloops", false, "check that range loop variables are used correctly"),
}
// vet tells whether to report errors for the named check, a flag name.
func vet(name string) bool {
return *report["all"] || *report[name]
}
// setExit sets the value for os.Exit when it is called, later. It
// remembers the highest value.
......@@ -66,8 +71,11 @@ func main() {
flag.Parse()
// If a check is named explicitly, turn off the 'all' flag.
if *vetAtomic || *vetBuildTags || *vetMethods || *vetPrintf || *vetStructTags || *vetRangeLoops || *vetUntaggedLiteral {
*vetAll = false
for name, ptr := range report {
if name != "all" && *ptr {
*report["all"] = false
break
}
}
if *printfuncs != "" {
......
......@@ -55,7 +55,7 @@ var canonicalMethods = map[string]MethodSig{
}
func (f *File) checkCanonicalMethod(id *ast.Ident, t *ast.FuncType) {
if !*vetMethods && !*vetAll {
if !vet("methods") {
return
}
// Expected input/output.
......@@ -161,9 +161,9 @@ func (f *File) matchParamType(expect string, actual ast.Expr) bool {
return f.b.String() == expect
}
func (t *BadTypeUsedInTests) Scan(x fmt.ScanState, c byte) { // ERROR "method Scan[(]x fmt.ScanState, c byte[)] should have signature Scan[(]fmt.ScanState, rune[)] error"
func (t *BadTypeUsedInTests) Scan(x fmt.ScanState, c byte) { // ERROR "should have signature Scan"
}
type BadInterfaceUsedInTests interface {
ReadByte() byte // ERROR "method ReadByte[(][)] byte should have signature ReadByte[(][)] [(]byte, error[)]"
ReadByte() byte // ERROR "should have signature ReadByte"
}
......@@ -44,7 +44,7 @@ var printList = map[string]int{
// checkCall triggers the print-specific checks if the call invokes a print function.
func (f *File) checkFmtPrintfCall(call *ast.CallExpr, Name string) {
if !*vetPrintf && !*vetAll {
if !vet("printf") {
return
}
name := strings.ToLower(Name)
......
......@@ -27,7 +27,7 @@ import "go/ast"
// its index or value variables are used unsafely inside goroutines or deferred
// function literals.
func checkRangeLoop(f *File, n *ast.RangeStmt) {
if !*vetRangeLoops && !*vetAll {
if !vet("rangeloops") {
return
}
key, _ := n.Key.(*ast.Ident)
......
......@@ -14,7 +14,7 @@ import (
// checkField checks a struct field tag.
func (f *File) checkCanonicalFieldTag(field *ast.Field) {
if !*vetStructTags && !*vetAll {
if !vet("structtags") {
return
}
if field.Tag == nil {
......@@ -37,5 +37,5 @@ func (f *File) checkCanonicalFieldTag(field *ast.Field) {
}
type BadTypeUsedInTests struct {
X int "hello" // ERROR "struct field tag"
X int "hello" // ERROR "not compatible with reflect.StructTag.Get"
}
......@@ -9,12 +9,14 @@ package main
import (
"go/ast"
"strings"
"flag" // for test
)
// checkUntaggedLiteral checks if a composite literal is an struct literal with
// untagged fields.
func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) {
if !*vetUntaggedLiteral && !*vetAll {
if !vet("composites") {
return
}
// Check if the CompositeLit contains an untagged field.
......@@ -123,6 +125,9 @@ var untaggedLiteralWhitelist = map[string]bool{
"image.Rectangle": true,
}
type BadTag struct {
S string `this is a bad tag` // ERROR "not compatible with reflect.StructTag.Get"
var BadStructLiteralUsedInTests = flag.Flag{ // ERROR "untagged fields"
"Name",
"Usage",
nil, // Value
"DefValue",
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment