Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: breml/errchkjson
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.2.2
Choose a base ref
...
head repository: breml/errchkjson
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.2.3
Choose a head ref
  • 4 commits
  • 6 files changed
  • 2 contributors

Commits on Feb 8, 2022

  1. Copy the full SHA
    68d82d6 View commit details
  2. Add version information

    Fixes #10
    breml committed Feb 8, 2022
    Copy the full SHA
    4f11bb1 View commit details
  3. Merge pull request #11 from breml/issue_9

    Handle types that implement json.Marshaler interface
    breml authored Feb 8, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f4f2a89 View commit details
  4. Merge pull request #12 from breml/issue_10

    Add version information
    breml authored Feb 8, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3aae218 View commit details
Showing with 126 additions and 5 deletions.
  1. +2 −0 .goreleaser.yml
  2. +31 −0 cmd/errchkjson/main.go
  3. +24 −3 errchkjson.go
  4. +25 −1 testdata/src/nosafe/a.go
  5. +25 −1 testdata/src/standard/a.go
  6. +19 −0 version.go
2 changes: 2 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -29,3 +29,5 @@ release:
github:
owner: breml
name: errchkjson
gomod:
proxy: true
31 changes: 31 additions & 0 deletions cmd/errchkjson/main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,42 @@
package main

import (
"fmt"
"os"
"path/filepath"
"runtime"
"runtime/debug"

"github.com/breml/errchkjson"

"golang.org/x/tools/go/analysis/singlechecker"
)

var (
version = "development"
commit = ""
date = ""
)

func main() {
errchkjson.Version = buildVersion()

singlechecker.Main(errchkjson.NewAnalyzer())
}

func buildVersion() string {
result := fmt.Sprintf("%s version %s", filepath.Base(os.Args[0]), version)

if commit != "" {
result = fmt.Sprintf("%s\ncommit: %s", result, commit)
}
if date != "" {
result = fmt.Sprintf("%s\nbuilt at: %s", result, date)
}
if info, ok := debug.ReadBuildInfo(); ok && info.Main.Sum != "" {
result = fmt.Sprintf("%s\nmodule version: %s, checksum: %s", result, info.Main.Version, info.Main.Sum)
}
result = fmt.Sprintf("%s\ngoos: %s\ngoarch: %s", result, runtime.GOOS, runtime.GOARCH)

return result
}
27 changes: 24 additions & 3 deletions errchkjson.go
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ func NewAnalyzer() *analysis.Analyzer {
a.Flags.Init("errchkjson", flag.ExitOnError)
a.Flags.BoolVar(&errchkjson.omitSafe, "omit-safe", false, "if omit-safe is true, checking of safe returns is omitted")
a.Flags.BoolVar(&errchkjson.reportNoExported, "report-no-exported", false, "if report-no-exported is true, encoding a struct without exported fields is reported as issue")
a.Flags.Var(versionFlag{}, "V", "print version and exit")

return a
}
@@ -154,7 +155,7 @@ func (e *errchkjson) jsonSafe(t types.Type, level int, seenTypes map[types.Type]
return nil
}

if types.Implements(t, textMarshalerInterface()) {
if types.Implements(t, textMarshalerInterface()) || types.Implements(t, jsonMarshalerInterface()) {
return fmt.Errorf("unsafe type `%s` found", t.String())
}

@@ -247,7 +248,7 @@ func (e *errchkjson) jsonSafe(t types.Type, level int, seenTypes map[types.Type]
}

func jsonSafeMapKey(t types.Type) error {
if types.Implements(t, textMarshalerInterface()) {
if types.Implements(t, textMarshalerInterface()) || types.Implements(t, jsonMarshalerInterface()) {
return fmt.Errorf("unsafe type `%s` as map key found", t.String())
}
switch ut := t.Underlying().(type) {
@@ -268,7 +269,7 @@ func jsonSafeMapKey(t types.Type) error {
}
}

// Construct *types.Interface for interface TextMarshaler
// Construct *types.Interface for interface encoding.TextMarshaler
// type TextMarshaler interface {
// MarshalText() (text []byte, err error)
// }
@@ -287,3 +288,23 @@ func textMarshalerInterface() *types.Interface {

return textMarshalerInterface
}

// Construct *types.Interface for interface json.Marshaler
// type Marshaler interface {
// MarshalJSON() ([]byte, error)
// }
//
func jsonMarshalerInterface() *types.Interface {
textMarshalerInterface := types.NewInterfaceType([]*types.Func{
types.NewFunc(token.NoPos, nil, "MarshalJSON", types.NewSignature(
nil, nil, types.NewTuple(
types.NewVar(token.NoPos, nil, "",
types.NewSlice(
types.Universe.Lookup("byte").Type())),
types.NewVar(token.NoPos, nil, "", types.Universe.Lookup("error").Type())),
false)),
}, nil)
textMarshalerInterface.Complete()

return textMarshalerInterface
}
26 changes: 25 additions & 1 deletion testdata/src/nosafe/a.go
Original file line number Diff line number Diff line change
@@ -10,12 +10,20 @@ import (

type marshalText struct{}

func (mt marshalText) MarshalText() ([]byte, error) {
func (_ marshalText) MarshalText() ([]byte, error) {
return []byte(`mt`), nil
}

var _ encoding.TextMarshaler = marshalText(struct{}{})

type marshalJSON struct{}

func (_ marshalJSON) MarshalJSON() ([]byte, error) {
return []byte(`mj`), nil
}

var _ json.Marshaler = marshalJSON(struct{}{})

// JSONMarshalSafeTypesWithNoSafe contains a multitude of test cases to marshal different combinations of types to JSON,
// that are safe, that is, they will never return an error, if these types are marshaled to JSON.
func JSONMarshalSafeTypesWithNoSafe() {
@@ -266,6 +274,8 @@ type (
Stringer fmt.Stringer
Mt marshalText
MapMarshalTextString map[marshalText]string
Mj marshalJSON
MapMarshalJSONString map[marshalJSON]string

C128 complex128
C128Ptr *complex128
@@ -301,6 +311,8 @@ func JSONMarshalSafeStructWithUnexportedFieldsWithNoSafe() {
stringer fmt.Stringer // unsafe unexported
mt marshalText // unsafe unexported
mapMarshalTextString map[marshalText]string // unsafe unexported
mj marshalJSON // unsafe unexported
mapMarshalJSONString map[marshalJSON]string // unsafe unexported
unexportedStruct ExportedUnsafeAndInvalidStruct // unsafe unexported
unexportedStructPtr *ExportedUnsafeAndInvalidStruct // unsafe unexported

@@ -366,6 +378,8 @@ func JSONMarshalSafeStructWithOmittedFieldsWithNoSafe() {
Stringer fmt.Stringer `json:"-"` // unsafe exported but omitted
Mt marshalText `json:"-"` // unsafe exported but omitted
MapMarshalTextString map[marshalText]string `json:"-"` // unsafe exported but omitted
Mj marshalJSON `json:"-"` // unsafe exported but omitted
MapMarshalJSONString map[marshalJSON]string `json:"-"` // unsafe exported but omitted
ExportedStruct ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
ExportedStructPtr *ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted

@@ -506,6 +520,16 @@ func JSONMarshalUnsafeTypes() {
_, _ = json.Marshal(mapMarshalTextString) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `nosafe.marshalText` as map key found"
_, err = json.Marshal(mapMarshalTextString) // err is checked
_ = err

var mj marshalJSON
_, _ = json.Marshal(mj) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `nosafe.marshalJSON` found"
_, err = json.Marshal(mj) // err is checked
_ = err

var mapMarshalJSONString map[marshalJSON]string
_, _ = json.Marshal(mapMarshalJSONString) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `nosafe.marshalJSON` as map key found"
_, err = json.Marshal(mapMarshalJSONString) // err is checked
_ = err
}

// JSONMarshalInvalidTypes contains a multitude of test cases to marshal different combinations of types to JSON,
26 changes: 25 additions & 1 deletion testdata/src/standard/a.go
Original file line number Diff line number Diff line change
@@ -10,12 +10,20 @@ import (

type marshalText struct{}

func (mt marshalText) MarshalText() ([]byte, error) {
func (_ marshalText) MarshalText() ([]byte, error) {
return []byte(`mt`), nil
}

var _ encoding.TextMarshaler = marshalText(struct{}{})

type marshalJSON struct{}

func (_ marshalJSON) MarshalJSON() ([]byte, error) {
return []byte(`mj`), nil
}

var _ json.Marshaler = marshalJSON(struct{}{})

// JSONMarshalSafeTypes contains a multitude of test cases to marshal different combinations of types to JSON,
// that are safe, that is, they will never return an error, if these types are marshaled to JSON.
func JSONMarshalSafeTypes() {
@@ -266,6 +274,8 @@ type (
Stringer fmt.Stringer
Mt marshalText
MapMarshalTextString map[marshalText]string
Mj marshalJSON
MapMarshalJSONString map[marshalJSON]string

C128 complex128
C128Ptr *complex128
@@ -301,6 +311,8 @@ func JSONMarshalSafeStructWithUnexportedFields() {
stringer fmt.Stringer // unsafe unexported
mt marshalText // unsafe unexported
mapMarshalTextString map[marshalText]string // unsafe unexported
mj marshalJSON // unsafe unexported
mapMarshalJSONString map[marshalJSON]string // unsafe unexported
unexportedStruct ExportedUnsafeAndInvalidStruct // unsafe unexported
unexportedStructPtr *ExportedUnsafeAndInvalidStruct // unsafe unexported

@@ -366,6 +378,8 @@ func JSONMarshalSafeStructWithOmittedFields() {
Stringer fmt.Stringer `json:"-"` // unsafe exported but omitted
Mt marshalText `json:"-"` // unsafe exported but omitted
MapMarshalTextString map[marshalText]string `json:"-"` // unsafe exported but omitted
Mj marshalJSON `json:"-"` // unsafe exported but omitted
MapMarshalJSONString map[marshalJSON]string `json:"-"` // unsafe exported but omitted
ExportedStruct ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
ExportedStructPtr *ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted

@@ -506,6 +520,16 @@ func JSONMarshalUnsafeTypes() {
_, _ = json.Marshal(mapMarshalTextString) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `standard.marshalText` as map key found"
_, err = json.Marshal(mapMarshalTextString) // err is checked
_ = err

var mj marshalJSON
_, _ = json.Marshal(mj) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `standard.marshalJSON` found"
_, err = json.Marshal(mj) // err is checked
_ = err

var mapMarshalJSONString map[marshalJSON]string
_, _ = json.Marshal(mapMarshalJSONString) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `standard.marshalJSON` as map key found"
_, err = json.Marshal(mapMarshalJSONString) // err is checked
_ = err
}

// JSONMarshalInvalidTypes contains a multitude of test cases to marshal different combinations of types to JSON,
19 changes: 19 additions & 0 deletions version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package errchkjson

import (
"fmt"
"os"
)

var Version = "errchkjson version dev"

type versionFlag struct{}

func (versionFlag) IsBoolFlag() bool { return true }
func (versionFlag) Get() interface{} { return nil }
func (versionFlag) String() string { return "" }
func (versionFlag) Set(s string) error {
fmt.Println(Version)
os.Exit(0)
return nil
}