Skip to content

Commit 4a8f079

Browse files
authored
feat: suppress reports from unexported interface methods (#52)
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.)
1 parent acb3e1f commit 4a8f079

File tree

2 files changed

+16
-10
lines changed

2 files changed

+16
-10
lines changed
Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
package main
22

3-
import (
4-
"encoding/json"
5-
"strings"
6-
)
7-
83
type errorer interface {
94
Decode(v interface{}) error
5+
decode(v interface{}) error
106
}
117

128
type foo struct {
139
bar errorer
1410
}
1511

1612
func main() {
17-
d := json.NewDecoder(strings.NewReader("hello world"))
18-
do(foo{d})
13+
do(foo{})
14+
doInternal(foo{})
1915
}
2016

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

2824
return nil
2925
}
26+
27+
func doInternal(f foo) error {
28+
var str string
29+
err := f.bar.decode(&str)
30+
if err != nil {
31+
return err // unexported methods are validated at their implementation
32+
}
33+
34+
return nil
35+
}

wrapcheck/wrapcheck.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,9 @@ func reportUnwrapped(
283283
}
284284

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

0 commit comments

Comments
 (0)