...
Source file src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
1
2
3
4
5
6
7 package unmarshal
8
9 import (
10 "go/ast"
11 "go/types"
12
13 "golang.org/x/tools/go/analysis"
14 "golang.org/x/tools/go/analysis/passes/inspect"
15 "golang.org/x/tools/go/ast/inspector"
16 "golang.org/x/tools/go/types/typeutil"
17 )
18
19 const doc = `report passing non-pointer or non-interface values to unmarshal
20
21 The unmarshal analysis reports calls to functions such as json.Unmarshal
22 in which the argument type is not a pointer or an interface.`
23
24 var Analyzer = &analysis.Analyzer{
25 Name: "unmarshal",
26 Doc: doc,
27 Requires: []*analysis.Analyzer{inspect.Analyzer},
28 Run: run,
29 }
30
31 func run(pass *analysis.Pass) (interface{}, error) {
32 switch pass.Pkg.Path() {
33 case "encoding/gob", "encoding/json", "encoding/xml":
34
35
36 return nil, nil
37 }
38
39 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
40
41 nodeFilter := []ast.Node{
42 (*ast.CallExpr)(nil),
43 }
44 inspect.Preorder(nodeFilter, func(n ast.Node) {
45 call := n.(*ast.CallExpr)
46 fn := typeutil.StaticCallee(pass.TypesInfo, call)
47 if fn == nil {
48 return
49 }
50
51
52 argidx := -1
53 recv := fn.Type().(*types.Signature).Recv()
54 if fn.Name() == "Unmarshal" && recv == nil {
55
56
57 switch fn.Pkg().Path() {
58 case "encoding/json", "encoding/xml":
59 argidx = 1
60 }
61 } else if fn.Name() == "Decode" && recv != nil {
62
63
64
65 t := recv.Type()
66 if ptr, ok := t.(*types.Pointer); ok {
67 t = ptr.Elem()
68 }
69 tname := t.(*types.Named).Obj()
70 if tname.Name() == "Decoder" {
71 switch tname.Pkg().Path() {
72 case "encoding/json", "encoding/xml", "encoding/gob":
73 argidx = 0
74 }
75 }
76 }
77 if argidx < 0 {
78 return
79 }
80
81 if len(call.Args) < argidx+1 {
82 return
83 }
84
85 t := pass.TypesInfo.Types[call.Args[argidx]].Type
86 switch t.Underlying().(type) {
87 case *types.Pointer, *types.Interface:
88 return
89 }
90
91 switch argidx {
92 case 0:
93 pass.Reportf(call.Lparen, "call of %s passes non-pointer", fn.Name())
94 case 1:
95 pass.Reportf(call.Lparen, "call of %s passes non-pointer as second argument", fn.Name())
96 }
97 })
98 return nil, nil
99 }
100
View as plain text