...
Run Format

Source file src/cmd/vet/composite.go

Documentation: cmd/vet

     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  }
    87  

View as plain text