src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

sa1026.go (2537B)


      1 package sa1026
      2 
      3 import (
      4 	"fmt"
      5 	"go/types"
      6 
      7 	"honnef.co/go/tools/analysis/callcheck"
      8 	"honnef.co/go/tools/analysis/lint"
      9 	"honnef.co/go/tools/internal/passes/buildir"
     10 	"honnef.co/go/tools/staticcheck/fakejson"
     11 	"honnef.co/go/tools/staticcheck/fakexml"
     12 
     13 	"golang.org/x/tools/go/analysis"
     14 )
     15 
     16 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
     17 	Analyzer: &analysis.Analyzer{
     18 		Name:     "SA1026",
     19 		Requires: []*analysis.Analyzer{buildir.Analyzer},
     20 		Run:      callcheck.Analyzer(rules),
     21 	},
     22 	Doc: &lint.RawDocumentation{
     23 		Title:    `Cannot marshal channels or functions`,
     24 		Since:    "2019.2",
     25 		Severity: lint.SeverityError,
     26 		MergeIf:  lint.MergeIfAny,
     27 	},
     28 })
     29 
     30 var Analyzer = SCAnalyzer.Analyzer
     31 
     32 var rules = map[string]callcheck.Check{
     33 	"encoding/json.Marshal":           checkJSON,
     34 	"encoding/json.MarshalIndent":     checkJSON,
     35 	"encoding/xml.Marshal":            checkXML,
     36 	"encoding/xml.MarshalIndent":      checkXML,
     37 	"(*encoding/json.Encoder).Encode": checkJSON,
     38 	"(*encoding/xml.Encoder).Encode":  checkXML,
     39 }
     40 
     41 func checkJSON(call *callcheck.Call) {
     42 	arg := call.Args[0]
     43 	T := arg.Value.Value.Type()
     44 	if err := fakejson.Marshal(T); err != nil {
     45 		typ := types.TypeString(err.Type, types.RelativeTo(call.Parent.Pkg.Pkg))
     46 		if err.Path == "x" {
     47 			arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ))
     48 		} else {
     49 			arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path))
     50 		}
     51 	}
     52 }
     53 
     54 func checkXML(call *callcheck.Call) {
     55 	arg := call.Args[0]
     56 	T := arg.Value.Value.Type()
     57 	if err := fakexml.Marshal(T); err != nil {
     58 		switch err := err.(type) {
     59 		case *fakexml.UnsupportedTypeError:
     60 			typ := types.TypeString(err.Type, types.RelativeTo(call.Parent.Pkg.Pkg))
     61 			if err.Path == "x" {
     62 				arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ))
     63 			} else {
     64 				arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path))
     65 			}
     66 		case *fakexml.CyclicTypeError:
     67 			typ := types.TypeString(err.Type, types.RelativeTo(call.Parent.Pkg.Pkg))
     68 			if err.Path == "x" {
     69 				arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s", typ))
     70 			} else {
     71 				arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s, via %s", typ, err.Path))
     72 			}
     73 		case *fakexml.TagPathError:
     74 			// Vet does a better job at reporting this error, because it can flag the actual struct tags, not just the call to Marshal
     75 		default:
     76 			// These errors get reported by SA5008 instead, which can flag the actual fields, independently of calls to xml.Marshal
     77 		}
     78 	}
     79 }