Commit 83e22f1a authored by Rob Pike's avatar Rob Pike

cmd/vet: eliminate false positives for slices in untagged literal test

Made possible by go/types, as long as the package type-checks OK.

Fixes #4684.

R=golang-dev
CC=golang-dev
https://golang.org/cl/7407045
parent b582ef38
...@@ -4,5 +4,5 @@ ...@@ -4,5 +4,5 @@
test testshort: test testshort:
go build -tags unsafe go build -tags unsafe
../../../test/errchk ./vet -printfuncs='Warn:1,Warnf:1' *.go ../../../test/errchk ./vet -compositewhitelist=false -printfuncs='Warn:1,Warnf:1' *.go
...@@ -7,18 +7,42 @@ ...@@ -7,18 +7,42 @@
package main package main
import ( import (
"flag"
"go/ast" "go/ast"
"go/types"
"strings" "strings"
"flag" // for test "go/scanner" // for test; chosen because it's already linked in.
) )
var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only")
// checkUntaggedLiteral checks if a composite literal is an struct literal with // checkUntaggedLiteral checks if a composite literal is an struct literal with
// untagged fields. // untagged fields.
func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) { func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) {
if !vet("composites") { if !vet("composites") {
return return
} }
// Check that the CompositeLit's type is a slice or array (which need no tag), if possible.
if f.pkg != nil {
typ := f.pkg.types[c]
if typ != nil {
// If it's a named type, pull out the underlying type.
if namedType, ok := typ.(*types.NamedType); ok {
typ = namedType.Underlying
}
switch typ.(type) {
case *types.Slice:
return
case *types.Array:
return
}
}
}
// It's a struct, or we can't tell it's not a struct because we don't have types.
// Check if the CompositeLit contains an untagged field. // Check if the CompositeLit contains an untagged field.
allKeyValue := true allKeyValue := true
for _, e := range c.Elts { for _, e := range c.Elts {
...@@ -48,11 +72,11 @@ func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) { ...@@ -48,11 +72,11 @@ func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) {
return return
} }
typ := path + "." + s.Sel.Name typ := path + "." + s.Sel.Name
if untaggedLiteralWhitelist[typ] { if *compositeWhiteList && untaggedLiteralWhitelist[typ] {
return return
} }
f.Warnf(c.Pos(), "%s struct literal uses untagged fields", typ) f.Warnf(c.Pos(), "%s composite literal uses untagged fields", typ)
} }
// pkgPath returns the import path "image/png" for the package name "png". // pkgPath returns the import path "image/png" for the package name "png".
...@@ -125,9 +149,17 @@ var untaggedLiteralWhitelist = map[string]bool{ ...@@ -125,9 +149,17 @@ var untaggedLiteralWhitelist = map[string]bool{
"image.Rectangle": true, "image.Rectangle": true,
} }
// Testing is awkward because we need to reference things from a separate package
// to trigger the warnings.
var BadStructLiteralUsedInTests = flag.Flag{ // ERROR "untagged fields" var BadStructLiteralUsedInTests = flag.Flag{ // ERROR "untagged fields"
"Name", "Name",
"Usage", "Usage",
nil, // Value nil, // Value
"DefValue", "DefValue",
} }
// Used to test the check for slices and arrays: If that test is disabled and
// vet is run with --compositewhitelist=false, this line triggers an error.
// Clumsy but sufficient.
var scannerErrorListTest = scanner.ErrorList{nil, nil}
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