diff --git a/builtin.go b/builtins.go similarity index 96% rename from builtin.go rename to builtins.go index b5c2346..50573f8 100644 --- a/builtin.go +++ b/builtins.go @@ -1,7 +1,7 @@ package musttag -// builtin is a set of functions supported out of the box. -var builtin = []Func{ +// builtins is a set of functions supported out of the box. +var builtins = []Func{ // https://pkg.go.dev/encoding/json {Name: "encoding/json.Marshal", Tag: "json", ArgPos: 0}, {Name: "encoding/json.MarshalIndent", Tag: "json", ArgPos: 0}, diff --git a/musttag.go b/musttag.go index 2b95705..c5b4d68 100644 --- a/musttag.go +++ b/musttag.go @@ -34,14 +34,14 @@ func New(funcs ...Func) *analysis.Analyzer { Flags: flags(&flagFuncs), Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: func(pass *analysis.Pass) (any, error) { - l := len(builtin) + len(funcs) + len(flagFuncs) + l := len(builtins) + len(funcs) + len(flagFuncs) m := make(map[string]Func, l) toMap := func(slice []Func) { for _, fn := range slice { m[fn.Name] = fn } } - toMap(builtin) + toMap(builtins) toMap(funcs) toMap(flagFuncs) return run(pass, m) @@ -84,9 +84,9 @@ var ( } // HACK(junk1tm): mainModulePackages() does not return packages from `testdata`, - // because it is ignored by the `go list` command. - // For tests to pass we need add these packages manually. - testPackages []string + // because it is ignored by the go tool, and thus, by the `go list` command. + // For tests to pass we need to add the package with tests to the main module manually. + testPackage string ) // run starts the analysis. @@ -95,8 +95,8 @@ func run(pass *analysis.Pass, funcs map[string]Func) (any, error) { if err != nil { return nil, err } - for _, pkg := range testPackages { - mainModule[pkg] = struct{}{} + if testPackage != "" { + mainModule[testPackage] = struct{}{} } // store previous reports to prevent reporting diff --git a/musttag_test.go b/musttag_test.go index 5b6092a..96b10e9 100644 --- a/musttag_test.go +++ b/musttag_test.go @@ -18,17 +18,16 @@ func TestAnalyzer(t *testing.T) { // So, to be able to run tests with external dependencies, // we first need to write a GOPATH-like tree of stubs. prepareTestFiles(t) - - testPackages = []string{"tests", "examples"} + testPackage = "tests" analyzer := New( Func{Name: "example.com/custom.Marshal", Tag: "custom", ArgPos: 0}, Func{Name: "example.com/custom.Unmarshal", Tag: "custom", ArgPos: 1}, ) - t.Run("examples", func(t *testing.T) { + t.Run("builtins", func(t *testing.T) { testdata := analysistest.TestData() - analysistest.Run(t, testdata, analyzer, "examples") + analysistest.Run(t, testdata, analyzer, "builtins") }) t.Run("tests", func(t *testing.T) { @@ -104,7 +103,7 @@ func prepareTestFiles(t *testing.T) { } } hardlink("tests", "tests.go") - hardlink("examples", "examples.go") + hardlink("builtins", "builtins.go") for file, data := range stubs { target := filepath.Join(testdata, "src", file) diff --git a/testdata/builtins.go b/testdata/builtins.go new file mode 100644 index 0000000..3bddf03 --- /dev/null +++ b/testdata/builtins.go @@ -0,0 +1,84 @@ +package tests + +import ( + "encoding/json" + "encoding/xml" + + // these packages are generated before the tests are run. + "example.com/custom" + "github.com/BurntSushi/toml" + "github.com/mitchellh/mapstructure" + "gopkg.in/yaml.v3" +) + +// TODO(junk1tm): drop `reportOnce` and test each builtin function. + +func testJSON() { + var user struct { // want `exported fields should be annotated with the "json" tag` + Name string + Email string `json:"email"` + } + json.Marshal(user) + json.MarshalIndent(user, "", "") + json.Unmarshal(nil, &user) + json.NewEncoder(nil).Encode(user) + json.NewDecoder(nil).Decode(&user) +} + +func testXML() { + var user struct { // want `exported fields should be annotated with the "xml" tag` + Name string + Email string `xml:"email"` + } + xml.Marshal(user) + xml.MarshalIndent(user, "", "") + xml.Unmarshal(nil, &user) + xml.NewEncoder(nil).Encode(user) + xml.NewDecoder(nil).Decode(&user) + xml.NewEncoder(nil).EncodeElement(user, xml.StartElement{}) + xml.NewDecoder(nil).DecodeElement(&user, &xml.StartElement{}) +} + +func testYAML() { + var user struct { // want `exported fields should be annotated with the "yaml" tag` + Name string + Email string `yaml:"email"` + } + yaml.Marshal(user) + yaml.Unmarshal(nil, &user) + yaml.NewEncoder(nil).Encode(user) + yaml.NewDecoder(nil).Decode(&user) +} + +func testTOML() { + var user struct { // want `exported fields should be annotated with the "toml" tag` + Name string + Email string `toml:"email"` + } + toml.Unmarshal(nil, &user) + toml.Decode("", &user) + toml.DecodeFS(nil, "", &user) + toml.DecodeFile("", &user) + toml.NewEncoder(nil).Encode(user) + toml.NewDecoder(nil).Decode(&user) +} + +func testMapstructure() { + var user struct { // want `exported fields should be annotated with the "mapstructure" tag` + Name string + Email string `mapstructure:"email"` + } + mapstructure.Decode(nil, &user) + mapstructure.DecodeMetadata(nil, &user, nil) + mapstructure.WeakDecode(nil, &user) + mapstructure.WeakDecodeMetadata(nil, &user, nil) +} + +func testCustom() { + var user struct { // want `exported fields should be annotated with the "custom" tag` + Name string + Email string `custom:"email"` + } + custom.Marshal(user) + custom.Unmarshal(nil, &user) +} diff --git a/testdata/examples.go b/testdata/examples.go deleted file mode 100644 index dbb113a..0000000 --- a/testdata/examples.go +++ /dev/null @@ -1,67 +0,0 @@ -package examples - -import ( - "encoding/json" - "encoding/xml" - - "example.com/custom" - "github.com/BurntSushi/toml" - "github.com/mitchellh/mapstructure" - "gopkg.in/yaml.v3" -) - -// make sure each example contains multiple calls but only one report. - -func exampleJSON() { - var user struct { // want `\Qexported fields should be annotated with the "json" tag` - Name string - Email string `json:"email"` - } - json.Marshal(user) - json.Unmarshal(nil, &user) -} - -func exampleXML() { - var user struct { // want `\Qexported fields should be annotated with the "xml" tag` - Name string - Email string `xml:"email"` - } - xml.Marshal(user) - xml.Unmarshal(nil, &user) -} - -func exampleYAML() { - var user struct { // want `\Qexported fields should be annotated with the "yaml" tag` - Name string - Email string `yaml:"email"` - } - yaml.Marshal(user) - yaml.Unmarshal(nil, &user) -} - -func exampleTOML() { - var user struct { // want `\Qexported fields should be annotated with the "toml" tag` - Name string - Email string `toml:"email"` - } - toml.Decode("", &user) - toml.Unmarshal(nil, &user) -} - -func exampleMS() { - var user struct { // want `\Qexported fields should be annotated with the "mapstructure" tag` - Name string - Email string `mapstructure:"email"` - } - mapstructure.Decode(nil, &user) - mapstructure.WeakDecode(nil, &user) -} - -func exampleCustom() { - var user struct { // want `\Qexported fields should be annotated with the "custom" tag` - Name string - Email string `custom:"email"` - } - custom.Marshal(user) - custom.Unmarshal(nil, &user) -} diff --git a/testdata/tests.go b/testdata/tests.go index 43faac5..8fedde5 100644 --- a/testdata/tests.go +++ b/testdata/tests.go @@ -1,486 +1,96 @@ package tests -import ( - "encoding/json" - "encoding/xml" - - "example.com/custom" - "github.com/BurntSushi/toml" - "github.com/mitchellh/mapstructure" - "gopkg.in/yaml.v3" -) - -var xmlSE xml.StartElement +import "encoding/json" func namedType() { - type X struct { /* want - `\Qjson.Marshal` - `\Qjson.MarshalIndent` - `\Qjson.Unmarshal` - `\Qjson.Encoder.Encode` - `\Qjson.Decoder.Decode` - - `\Qxml.Marshal` - `\Qxml.MarshalIndent` - `\Qxml.Unmarshal` - `\Qxml.Encoder.Encode` - `\Qxml.Decoder.Decode` - `\Qxml.Encoder.EncodeElement` - `\Qxml.Decoder.DecodeElement` - - `\Qyaml.v3.Marshal` - `\Qyaml.v3.Unmarshal` - `\Qyaml.v3.Encoder.Encode` - `\Qyaml.v3.Decoder.Decode` - - `\Qtoml.Unmarshal` - `\Qtoml.Decode` - `\Qtoml.DecodeFS` - `\Qtoml.DecodeFile` - `\Qtoml.Encoder.Encode` - `\Qtoml.Decoder.Decode` - - `\Qmapstructure.Decode` - `\Qmapstructure.DecodeMetadata` - `\Qmapstructure.WeakDecode` - `\Qmapstructure.WeakDecodeMetadata` - - `\Qcustom.Marshal` - `\Qcustom.Unmarshal` */ - NoTag int - } - var x X - - json.Marshal(x) - json.MarshalIndent(x, "", "") - json.Unmarshal(nil, &x) - json.NewEncoder(nil).Encode(X{}) - json.NewDecoder(nil).Decode(&X{}) - - xml.Marshal(x) - xml.MarshalIndent(x, "", "") - xml.Unmarshal(nil, &x) - xml.NewEncoder(nil).Encode(X{}) - xml.NewDecoder(nil).Decode(&X{}) - xml.NewEncoder(nil).EncodeElement(X{}, xmlSE) - xml.NewDecoder(nil).DecodeElement(&X{}, &xmlSE) - - yaml.Marshal(x) - yaml.Unmarshal(nil, &x) - yaml.NewEncoder(nil).Encode(X{}) - yaml.NewDecoder(nil).Decode(&X{}) - - toml.Unmarshal(nil, &x) - toml.Decode("", &x) - toml.DecodeFS(nil, "", &x) - toml.DecodeFile("", &x) - toml.NewEncoder(nil).Encode(X{}) - toml.NewDecoder(nil).Decode(&X{}) - - mapstructure.Decode(nil, &x) - mapstructure.DecodeMetadata(nil, &x, nil) - mapstructure.WeakDecode(nil, &X{}) - mapstructure.WeakDecodeMetadata(nil, &X{}, nil) - - custom.Marshal(x) - custom.Unmarshal(nil, &x) -} - -func nestedNamedType() { - type Y struct { /* want - `\Qjson.Marshal` - `\Qjson.MarshalIndent` - `\Qjson.Unmarshal` - `\Qjson.Encoder.Encode` - `\Qjson.Decoder.Decode` - - `\Qxml.Marshal` - `\Qxml.MarshalIndent` - `\Qxml.Unmarshal` - `\Qxml.Encoder.Encode` - `\Qxml.Decoder.Decode` - `\Qxml.Encoder.EncodeElement` - `\Qxml.Decoder.DecodeElement` - - `\Qyaml.v3.Marshal` - `\Qyaml.v3.Unmarshal` - `\Qyaml.v3.Encoder.Encode` - `\Qyaml.v3.Decoder.Decode` - - `\Qtoml.Unmarshal` - `\Qtoml.Decode` - `\Qtoml.DecodeFS` - `\Qtoml.DecodeFile` - `\Qtoml.Encoder.Encode` - `\Qtoml.Decoder.Decode` - - `\Qmapstructure.Decode` - `\Qmapstructure.DecodeMetadata` - `\Qmapstructure.WeakDecode` - `\Qmapstructure.WeakDecodeMetadata` - - `\Qcustom.Marshal` - `\Qcustom.Unmarshal` */ - NoTag int - } - type X struct { - Y Y `json:"y" xml:"y" yaml:"y" toml:"y" mapstructure:"y" custom:"y"` + type Foo struct { // want `json.Marshal` `json.Unmarshal` `json.Encoder.Encode` `json.Decoder.Decode` + NoTag string } - var x X - - json.Marshal(x) - json.MarshalIndent(x, "", "") - json.Unmarshal(nil, &x) - json.NewEncoder(nil).Encode(X{}) - json.NewDecoder(nil).Decode(&X{}) - - xml.Marshal(x) - xml.MarshalIndent(x, "", "") - xml.Unmarshal(nil, &x) - xml.NewEncoder(nil).Encode(X{}) - xml.NewDecoder(nil).Decode(&X{}) - xml.NewEncoder(nil).EncodeElement(X{}, xmlSE) - xml.NewDecoder(nil).DecodeElement(&X{}, &xmlSE) - - yaml.Marshal(x) - yaml.Unmarshal(nil, &x) - yaml.NewEncoder(nil).Encode(X{}) - yaml.NewDecoder(nil).Decode(&X{}) - - toml.Unmarshal(nil, &x) - toml.Decode("", &x) - toml.DecodeFS(nil, "", &x) - toml.DecodeFile("", &x) - toml.NewEncoder(nil).Encode(X{}) - toml.NewDecoder(nil).Decode(&X{}) - - mapstructure.Decode(nil, &x) - mapstructure.DecodeMetadata(nil, &x, nil) - mapstructure.WeakDecode(nil, &X{}) - mapstructure.WeakDecodeMetadata(nil, &X{}, nil) - - custom.Marshal(x) - custom.Unmarshal(nil, &x) + var foo Foo + json.Marshal(foo) + json.Unmarshal(nil, &foo) + json.NewEncoder(nil).Encode(Foo{}) + json.NewDecoder(nil).Decode(&Foo{}) } func anonymousType() { - var x struct { /* want - `\Qjson.Marshal` - `\Qjson.MarshalIndent` - `\Qjson.Unmarshal` - - `\Qxml.Marshal` - `\Qxml.MarshalIndent` - `\Qxml.Unmarshal` - - `\Qyaml.v3.Marshal` - `\Qyaml.v3.Unmarshal` - - `\Qtoml.Unmarshal` - `\Qtoml.Decode` - `\Qtoml.DecodeFS` - `\Qtoml.DecodeFile` - - `\Qmapstructure.Decode` - `\Qmapstructure.DecodeMetadata` - - `\Qcustom.Marshal` - `\Qcustom.Unmarshal` */ - NoTag int + var foo struct { // want `json.Marshal` `json.Unmarshal` + NoTag string } - - json.Marshal(x) - json.MarshalIndent(x, "", "") - json.Unmarshal(nil, &x) - json.NewEncoder(nil).Encode(struct{ NoTag int }{}) // want `\Qjson.Encoder.Encode` - json.NewDecoder(nil).Decode(&struct{ NoTag int }{}) // want `\Qjson.Decoder.Decode` - - xml.Marshal(x) - xml.MarshalIndent(x, "", "") - xml.Unmarshal(nil, &x) - xml.NewEncoder(nil).Encode(struct{ NoTag int }{}) // want `\Qxml.Encoder.Encode` - xml.NewDecoder(nil).Decode(&struct{ NoTag int }{}) // want `\Qxml.Decoder.Decode` - xml.NewEncoder(nil).EncodeElement(struct{ NoTag int }{}, xmlSE) // want `\Qxml.Encoder.EncodeElement` - xml.NewDecoder(nil).DecodeElement(&struct{ NoTag int }{}, &xmlSE) // want `\Qxml.Decoder.DecodeElement` - - yaml.Marshal(x) - yaml.Unmarshal(nil, &x) - yaml.NewEncoder(nil).Encode(struct{ NoTag int }{}) // want `\Qyaml.v3.Encoder.Encode` - yaml.NewDecoder(nil).Decode(&struct{ NoTag int }{}) // want `\Qyaml.v3.Decoder.Decode` - - toml.Unmarshal(nil, &x) - toml.Decode("", &x) - toml.DecodeFS(nil, "", &x) - toml.DecodeFile("", &x) - toml.NewEncoder(nil).Encode(struct{ NoTag int }{}) // want `\Qtoml.Encoder.Encode` - toml.NewDecoder(nil).Decode(&struct{ NoTag int }{}) // want `\Qtoml.Decoder.Decode` - - mapstructure.Decode(nil, &x) - mapstructure.DecodeMetadata(nil, &x, nil) - mapstructure.WeakDecode(nil, &struct{ NoTag int }{}) // want `\Qmapstructure.WeakDecode` - mapstructure.WeakDecodeMetadata(nil, &struct{ NoTag int }{}, nil) // want `\Qmapstructure.WeakDecodeMetadata` - - custom.Marshal(x) - custom.Unmarshal(nil, &x) + json.Marshal(foo) + json.Unmarshal(nil, &foo) + json.NewEncoder(nil).Encode(struct{ NoTag int }{}) // want `json.Encoder.Encode` + json.NewDecoder(nil).Decode(&struct{ NoTag int }{}) // want `json.Decoder.Decode` } -func nestedAnonymousType() { - var x struct { /* want - `\Qjson.Marshal` - `\Qjson.MarshalIndent` - `\Qjson.Unmarshal` - - `\Qxml.Marshal` - `\Qxml.MarshalIndent` - `\Qxml.Unmarshal` - - `\Qyaml.v3.Marshal` - `\Qyaml.v3.Unmarshal` - - `\Qtoml.Unmarshal` - `\Qtoml.Decode` - `\Qtoml.DecodeFS` - `\Qtoml.DecodeFile` - - `\Qmapstructure.Decode` - `\Qmapstructure.DecodeMetadata` - - `\Qcustom.Marshal` - `\Qcustom.Unmarshal` */ - Y *struct{ NoTag int } `json:"y" xml:"y" yaml:"y" toml:"y" mapstructure:"y" custom:"y"` +func nestedType() { + type Bar struct { // want `json.Marshal` `json.Unmarshal` `json.Encoder.Encode` `json.Decoder.Decode` + Baz struct{ NoTag string } `json:"baz"` } - - json.Marshal(x) - json.MarshalIndent(x, "", "") - json.Unmarshal(nil, &x) - json.NewEncoder(nil).Encode(struct{ Y struct{ NoTag int } }{}) // want `\Qjson.Encoder.Encode` - json.NewDecoder(nil).Decode(&struct{ Y struct{ NoTag int } }{}) // want `\Qjson.Decoder.Decode` - - xml.Marshal(x) - xml.MarshalIndent(x, "", "") - xml.Unmarshal(nil, &x) - xml.NewEncoder(nil).Encode(struct{ Y struct{ NoTag int } }{}) // want `\Qxml.Encoder.Encode` - xml.NewDecoder(nil).Decode(&struct{ Y struct{ NoTag int } }{}) // want `\Qxml.Decoder.Decode` - xml.NewEncoder(nil).EncodeElement(struct{ Y struct{ NoTag int } }{}, xmlSE) // want `\Qxml.Encoder.EncodeElement` - xml.NewDecoder(nil).DecodeElement(&struct{ Y struct{ NoTag int } }{}, &xmlSE) // want `\Qxml.Decoder.DecodeElement` - - yaml.Marshal(x) - yaml.Unmarshal(nil, &x) - yaml.NewEncoder(nil).Encode(struct{ Y struct{ NoTag int } }{}) // want `\Qyaml.v3.Encoder.Encode` - yaml.NewDecoder(nil).Decode(&struct{ Y struct{ NoTag int } }{}) // want `\Qyaml.v3.Decoder.Decode` - - toml.Unmarshal(nil, &x) - toml.Decode("", &x) - toml.DecodeFS(nil, "", &x) - toml.DecodeFile("", &x) - toml.NewEncoder(nil).Encode(struct{ Y struct{ NoTag int } }{}) // want `\Qtoml.Encoder.Encode` - toml.NewDecoder(nil).Decode(&struct{ Y struct{ NoTag int } }{}) // want `\Qtoml.Decoder.Decode` - - mapstructure.Decode(nil, &x) - mapstructure.DecodeMetadata(nil, &x, nil) - mapstructure.WeakDecode(nil, &struct{ Y struct{ NoTag int } }{}) // want `\Qmapstructure.WeakDecode` - mapstructure.WeakDecodeMetadata(nil, &struct{ Y struct{ NoTag int } }{}, nil) // want `\Qmapstructure.WeakDecodeMetadata` - - custom.Marshal(x) - custom.Unmarshal(nil, &x) + type Foo struct { + Bar ***Bar `json:"bar"` + } + var foo Foo + json.Marshal(foo) + json.Unmarshal(nil, &foo) + json.NewEncoder(nil).Encode(Foo{}) + json.NewDecoder(nil).Decode(&Foo{}) } -// embedded types should not be reported. func embeddedType() { - type Y struct { /* want - `\Qjson.Marshal` - `\Qjson.MarshalIndent` - `\Qjson.Unmarshal` - `\Qjson.Encoder.Encode` - `\Qjson.Decoder.Decode` - - `\Qxml.Marshal` - `\Qxml.MarshalIndent` - `\Qxml.Unmarshal` - `\Qxml.Encoder.Encode` - `\Qxml.Decoder.Decode` - `\Qxml.Encoder.EncodeElement` - `\Qxml.Decoder.DecodeElement` - - `\Qyaml.v3.Marshal` - `\Qyaml.v3.Unmarshal` - `\Qyaml.v3.Encoder.Encode` - `\Qyaml.v3.Decoder.Decode` - - `\Qtoml.Unmarshal` - `\Qtoml.Decode` - `\Qtoml.DecodeFS` - `\Qtoml.DecodeFile` - `\Qtoml.Encoder.Encode` - `\Qtoml.Decoder.Decode` - - `\Qmapstructure.Decode` - `\Qmapstructure.DecodeMetadata` - `\Qmapstructure.WeakDecode` - `\Qmapstructure.WeakDecodeMetadata` - - `\Qcustom.Marshal` - `\Qcustom.Unmarshal` */ - NoTag int + type Bar struct { // want `json.Marshal` `json.Unmarshal` `json.Encoder.Encode` `json.Decoder.Decode` + NoTag string } - var x struct { - Y - Z int `json:"z" xml:"z" yaml:"z" toml:"z" mapstructure:"z" custom:"z"` + type Foo struct { + Bar } - - json.Marshal(x) - json.MarshalIndent(x, "", "") - json.Unmarshal(nil, &x) - json.NewEncoder(nil).Encode(x) - json.NewDecoder(nil).Decode(&x) - - xml.Marshal(x) - xml.MarshalIndent(x, "", "") - xml.Unmarshal(nil, &x) - xml.NewEncoder(nil).Encode(x) - xml.NewDecoder(nil).Decode(&x) - xml.NewEncoder(nil).EncodeElement(x, xmlSE) - xml.NewDecoder(nil).DecodeElement(&x, &xmlSE) - - yaml.Marshal(x) - yaml.Unmarshal(nil, &x) - yaml.NewEncoder(nil).Encode(x) - yaml.NewDecoder(nil).Decode(&x) - - toml.Unmarshal(nil, &x) - toml.Decode("", &x) - toml.DecodeFS(nil, "", &x) - toml.DecodeFile("", &x) - toml.NewEncoder(nil).Encode(x) - toml.NewDecoder(nil).Decode(&x) - - mapstructure.Decode(nil, &x) - mapstructure.DecodeMetadata(nil, &x, nil) - mapstructure.WeakDecode(nil, &x) - mapstructure.WeakDecodeMetadata(nil, &x, nil) - - custom.Marshal(x) - custom.Unmarshal(nil, &x) + var foo Foo + json.Marshal(foo) + json.Unmarshal(nil, &foo) + json.NewEncoder(nil).Encode(Foo{}) + json.NewDecoder(nil).Decode(&Foo{}) } -// all good, nothing to report. -func typeWithAllTags() { - var x struct { - Y int `json:"y" xml:"y" yaml:"y" toml:"y" mapstructure:"y" custom:"y"` - Z int `json:"z" xml:"z" yaml:"z" toml:"z" mapstructure:"z" custom:"z"` - Nested struct{} `json:"nested" xml:"nested" yaml:"nested" toml:"nested" mapstructure:"nested" custom:"nested"` - private int +// should not cause panic; see issue #16. +func recursiveType() { + type Foo struct { // want `json.Marshal` `json.Unmarshal` `json.Encoder.Encode` `json.Decoder.Decode` + Foo2 *Foo `json:"foo2"` + NoTag string } - - json.Marshal(x) - json.MarshalIndent(x, "", "") - json.Unmarshal(nil, &x) - json.NewEncoder(nil).Encode(x) - json.NewDecoder(nil).Decode(&x) - - xml.Marshal(x) - xml.MarshalIndent(x, "", "") - xml.Unmarshal(nil, &x) - xml.NewEncoder(nil).Encode(x) - xml.NewDecoder(nil).Decode(&x) - xml.NewEncoder(nil).EncodeElement(x, xmlSE) - xml.NewDecoder(nil).DecodeElement(&x, &xmlSE) - - yaml.Marshal(x) - yaml.Unmarshal(nil, &x) - yaml.NewEncoder(nil).Encode(x) - yaml.NewDecoder(nil).Decode(&x) - - toml.Unmarshal(nil, &x) - toml.Decode("", &x) - toml.DecodeFS(nil, "", &x) - toml.DecodeFile("", &x) - toml.NewEncoder(nil).Encode(x) - toml.NewDecoder(nil).Decode(&x) - - mapstructure.Decode(nil, &x) - mapstructure.DecodeMetadata(nil, &x, nil) - mapstructure.WeakDecode(nil, &x) - mapstructure.WeakDecodeMetadata(nil, &x, nil) - - custom.Marshal(x) - custom.Unmarshal(nil, &x) + var foo Foo + json.Marshal(foo) + json.Unmarshal(nil, &foo) + json.NewEncoder(nil).Encode(Foo{}) + json.NewDecoder(nil).Decode(&Foo{}) } -// non-static calls should be ignored. -func nonStaticCalls() { - var x struct { +func shouldBeIgnored() { + type Foo struct { NoTag int } - + var foo Foo marshalJSON := json.Marshal - marshalJSON(x) - - marshalXML := xml.Marshal - marshalXML(x) - - marshalYAML := yaml.Marshal - marshalYAML(x) - - unmarshalTOML := toml.Unmarshal - unmarshalTOML(nil, &x) - - decodeMS := mapstructure.Decode - decodeMS(nil, &x) - - marshalCustom := custom.Marshal - marshalCustom(x) + marshalJSON(foo) // a non-static call. + json.Marshal(0) // a non-struct argument. + json.Marshal(nil) // nil argument, see issue #20. } -// non-struct argument calls should be ignored. -func nonStructArgument() { - json.Marshal(0) - json.MarshalIndent("", "", "") - json.Unmarshal(nil, &[]int{}) - json.NewEncoder(nil).Encode(map[int]int{}) - json.NewDecoder(nil).Decode(&map[int]int{}) - - xml.Marshal(0) - xml.MarshalIndent("", "", "") - xml.Unmarshal(nil, &[]int{}) - xml.NewEncoder(nil).Encode(map[int]int{}) - xml.NewDecoder(nil).Decode(&map[int]int{}) - xml.NewEncoder(nil).EncodeElement(map[int]int{}, xmlSE) - xml.NewDecoder(nil).DecodeElement(&map[int]int{}, &xmlSE) - - yaml.Marshal(0) - yaml.Unmarshal(nil, &[]int{}) - yaml.NewEncoder(nil).Encode(map[int]int{}) - yaml.NewDecoder(nil).Decode(&map[int]int{}) - - toml.Unmarshal(nil, &[]int{}) - toml.Decode("", &[]int{}) - toml.DecodeFS(nil, "", &[]int{}) - toml.DecodeFile("", &[]int{}) - toml.NewEncoder(nil).Encode(map[int]int{}) - toml.NewDecoder(nil).Decode(&map[int]int{}) - - mapstructure.Decode(nil, &[]int{}) - mapstructure.DecodeMetadata(nil, &[]int{}, nil) - mapstructure.WeakDecode(nil, &map[int]int{}) - mapstructure.WeakDecodeMetadata(nil, &map[int]int{}, nil) - - custom.Marshal(0) - custom.Unmarshal(nil, &[]int{}) -} - -// test for panic with nil object issue: https://github.com/junk1tm/musttag/issues/20 -func nilObject() { - json.Marshal(nil) -} - -// test for stack overflow issue: https://github.com/junk1tm/musttag/issues/16 -func selfType() { - type Human struct { - Mom *Human `json:"mom"` - Dad *Human `json:"dad"` - Children []*Human `json:"children"` +func nothingToReport() { + type Bar struct { + B string `json:"b"` + Bar struct { + C string `json:"c"` + } `json:"bar"` + } + type Foo struct { + Bar + A string `json:"a"` + private string + _ string } - var v *Human - json.Marshal(v) + var foo Foo + json.Marshal(foo) + json.Unmarshal(nil, &foo) + json.NewEncoder(nil).Encode(Foo{}) + json.NewDecoder(nil).Decode(&Foo{}) }