// Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file contains the test for unkeyed struct literals. package govet import ( "flag" "go/ast" "go/types" "strings" "github.com/golangci/govet/lib/whitelist" ) var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only") func init() { register("composites", "check that composite literals used field-keyed elements", checkUnkeyedLiteral, compositeLit) } // checkUnkeyedLiteral checks if a composite literal is a struct literal with // unkeyed fields. func checkUnkeyedLiteral(f *File, node ast.Node) { if strings.HasSuffix(f.name, "_test.go") { return } cl := node.(*ast.CompositeLit) typ := f.pkg.types[cl].Type if typ == nil { // cannot determine composite literals' type, skip it return } typeName := typ.String() if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] { // skip whitelisted types return } under := typ.Underlying() for { ptr, ok := under.(*types.Pointer) if !ok { break } under = ptr.Elem().Underlying() } if _, ok := under.(*types.Struct); !ok { // skip non-struct composite literals return } if isLocalType(f, typ) { // allow unkeyed locally defined composite literal return } // check if the CompositeLit contains an unkeyed field allKeyValue := true for _, e := range cl.Elts { if _, ok := e.(*ast.KeyValueExpr); !ok { allKeyValue = false break } } if allKeyValue { // all the composite literal fields are keyed return } f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", types.TypeString(typ, func(pkg *types.Package) string { return pkg.Name() })) } func isLocalType(f *File, typ types.Type) bool { switch x := typ.(type) { case *types.Struct: // struct literals are local types return true case *types.Pointer: return isLocalType(f, x.Elem()) case *types.Named: // names in package foo are local to foo_test too return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(f.pkg.typesPkg.Path(), "_test") } return false }