github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/cmd/vet/composite.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file contains the test for unkeyed struct literals. 6 7 package main 8 9 import ( 10 "cmd/vet/internal/whitelist" 11 "flag" 12 "go/ast" 13 "go/types" 14 "strings" 15 ) 16 17 var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only") 18 19 func init() { 20 register("composites", 21 "check that composite literals of types from imported packages use field-keyed elements", 22 checkUnkeyedLiteral, 23 compositeLit) 24 } 25 26 // checkUnkeyedLiteral checks if a composite literal is a struct literal with 27 // unkeyed fields. 28 func checkUnkeyedLiteral(f *File, node ast.Node) { 29 cl := node.(*ast.CompositeLit) 30 31 typ := f.pkg.types[cl].Type 32 if typ == nil { 33 // cannot determine composite literals' type, skip it 34 return 35 } 36 typeName := typ.String() 37 if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] { 38 // skip whitelisted types 39 return 40 } 41 under := typ.Underlying() 42 for { 43 ptr, ok := under.(*types.Pointer) 44 if !ok { 45 break 46 } 47 under = ptr.Elem().Underlying() 48 } 49 if _, ok := under.(*types.Struct); !ok { 50 // skip non-struct composite literals 51 return 52 } 53 if isLocalType(f, typ) { 54 // allow unkeyed locally defined composite literal 55 return 56 } 57 58 // check if the CompositeLit contains an unkeyed field 59 allKeyValue := true 60 for _, e := range cl.Elts { 61 if _, ok := e.(*ast.KeyValueExpr); !ok { 62 allKeyValue = false 63 break 64 } 65 } 66 if allKeyValue { 67 // all the composite literal fields are keyed 68 return 69 } 70 71 f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName) 72 } 73 74 func isLocalType(f *File, typ types.Type) bool { 75 switch x := typ.(type) { 76 case *types.Struct: 77 // struct literals are local types 78 return true 79 case *types.Pointer: 80 return isLocalType(f, x.Elem()) 81 case *types.Named: 82 // names in package foo are local to foo_test too 83 return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(f.pkg.path, "_test") 84 } 85 return false 86 }