...
Source file src/pkg/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go
1
2
3
4
5
6
7 package composite
8
9 import (
10 "go/ast"
11 "go/types"
12 "strings"
13
14 "golang.org/x/tools/go/analysis"
15 "golang.org/x/tools/go/analysis/passes/inspect"
16 "golang.org/x/tools/go/ast/inspector"
17 )
18
19 const Doc = `check for unkeyed composite literals
20
21 This analyzer reports a diagnostic for composite literals of struct
22 types imported from another package that do not use the field-keyed
23 syntax. Such literals are fragile because the addition of a new field
24 (even if unexported) to the struct will cause compilation to fail.
25
26 As an example,
27
28 err = &net.DNSConfigError{err}
29
30 should be replaced by:
31
32 err = &net.DNSConfigError{Err: err}
33 `
34
35 var Analyzer = &analysis.Analyzer{
36 Name: "composites",
37 Doc: Doc,
38 Requires: []*analysis.Analyzer{inspect.Analyzer},
39 RunDespiteErrors: true,
40 Run: run,
41 }
42
43 var whitelist = true
44
45 func init() {
46 Analyzer.Flags.BoolVar(&whitelist, "whitelist", whitelist, "use composite white list; for testing only")
47 }
48
49
50
51 func run(pass *analysis.Pass) (interface{}, error) {
52 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
53
54 nodeFilter := []ast.Node{
55 (*ast.CompositeLit)(nil),
56 }
57 inspect.Preorder(nodeFilter, func(n ast.Node) {
58 cl := n.(*ast.CompositeLit)
59
60 typ := pass.TypesInfo.Types[cl].Type
61 if typ == nil {
62
63 return
64 }
65 typeName := typ.String()
66 if whitelist && unkeyedLiteral[typeName] {
67
68 return
69 }
70 under := typ.Underlying()
71 for {
72 ptr, ok := under.(*types.Pointer)
73 if !ok {
74 break
75 }
76 under = ptr.Elem().Underlying()
77 }
78 if _, ok := under.(*types.Struct); !ok {
79
80 return
81 }
82 if isLocalType(pass, typ) {
83
84 return
85 }
86
87
88 allKeyValue := true
89 for _, e := range cl.Elts {
90 if _, ok := e.(*ast.KeyValueExpr); !ok {
91 allKeyValue = false
92 break
93 }
94 }
95 if allKeyValue {
96
97 return
98 }
99
100 pass.Reportf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName)
101 })
102 return nil, nil
103 }
104
105 func isLocalType(pass *analysis.Pass, typ types.Type) bool {
106 switch x := typ.(type) {
107 case *types.Struct:
108
109 return true
110 case *types.Pointer:
111 return isLocalType(pass, x.Elem())
112 case *types.Named:
113
114 return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test")
115 }
116 return false
117 }
118
View as plain text