Skip to content

Commit

Permalink
feat: suppress reports from unexported interface methods (#52)
Browse files Browse the repository at this point in the history
When an interface method is not exported, its only implementations will
be local to the module under analysis. Thus, the implementations can be
checked, and the caller can assume the error was wrapped.

This reasoning does not apply to exported interface methods, even if the
interface happens to also have an unexported method. (An implementation
can override just the public methods by embedding the interface or a
struct that implements it.)
  • Loading branch information
MichaelUrman authored Jul 16, 2024
1 parent acb3e1f commit 4a8f079
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 10 deletions.
20 changes: 13 additions & 7 deletions wrapcheck/testdata/interface_on_struct/main.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
package main

import (
"encoding/json"
"strings"
)

type errorer interface {
Decode(v interface{}) error
decode(v interface{}) error
}

type foo struct {
bar errorer
}

func main() {
d := json.NewDecoder(strings.NewReader("hello world"))
do(foo{d})
do(foo{})
doInternal(foo{})
}

func do(f foo) error {
Expand All @@ -27,3 +23,13 @@ func do(f foo) error {

return nil
}

func doInternal(f foo) error {
var str string
err := f.bar.decode(&str)
if err != nil {
return err // unexported methods are validated at their implementation
}

return nil
}
6 changes: 3 additions & 3 deletions wrapcheck/wrapcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,9 @@ func reportUnwrapped(
}

// Check if the underlying type of the "x" in x.y.z is an interface, as
// errors returned from interface types should be wrapped, unless ignored
// as per `ignoreInterfaceRegexps`
if isInterface(pass, sel) {
// errors returned from exported interface types should be wrapped, unless
// ignored as per `ignoreInterfaceRegexps`
if sel.Sel.IsExported() && isInterface(pass, sel) {
pkgPath := pass.TypesInfo.ObjectOf(sel.Sel).Pkg().Path()
name := types.TypeString(pass.TypesInfo.TypeOf(sel.X), func(p *types.Package) string { return p.Name() })
if !containsMatch(regexpsInter, name) && !containsMatchGlob(pkgGlobs, pkgPath) {
Expand Down

0 comments on commit 4a8f079

Please sign in to comment.