github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/cmd/vet/unmarshal.go (about) 1 // Copyright 2018 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 defines the check for passing non-pointer or non-interface 6 // types to unmarshal and decode functions. 7 8 package main 9 10 import ( 11 "go/ast" 12 "go/types" 13 "strings" 14 ) 15 16 func init() { 17 register("unmarshal", 18 "check for passing non-pointer or non-interface types to unmarshal and decode functions", 19 checkUnmarshalArg, 20 callExpr) 21 } 22 23 var pointerArgFuncs = map[string]int{ 24 "encoding/json.Unmarshal": 1, 25 "(*encoding/json.Decoder).Decode": 0, 26 "(*encoding/gob.Decoder).Decode": 0, 27 "encoding/xml.Unmarshal": 1, 28 "(*encoding/xml.Decoder).Decode": 0, 29 } 30 31 func checkUnmarshalArg(f *File, n ast.Node) { 32 call, ok := n.(*ast.CallExpr) 33 if !ok { 34 return // not a call statement 35 } 36 fun := unparen(call.Fun) 37 38 if f.pkg.types[fun].IsType() { 39 return // a conversion, not a call 40 } 41 42 info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors} 43 name := callName(info, call) 44 45 arg, ok := pointerArgFuncs[name] 46 if !ok { 47 return // not a function we are interested in 48 } 49 50 if len(call.Args) < arg+1 { 51 return // not enough arguments, e.g. called with return values of another function 52 } 53 54 typ := f.pkg.types[call.Args[arg]] 55 56 if typ.Type == nil { 57 return // type error prevents further analysis 58 } 59 60 switch typ.Type.Underlying().(type) { 61 case *types.Pointer, *types.Interface: 62 return 63 } 64 65 shortname := name[strings.LastIndexByte(name, '.')+1:] 66 switch arg { 67 case 0: 68 f.Badf(call.Lparen, "call of %s passes non-pointer", shortname) 69 case 1: 70 f.Badf(call.Lparen, "call of %s passes non-pointer as second argument", shortname) 71 } 72 }