Skip to content

Commit 067f50b

Browse files
committed
feat: add option for reporting internal errors
1 parent 2ddbe2e commit 067f50b

4 files changed

Lines changed: 96 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ ignorePackageGlobs:
6868
# function whose call is defined on the given interface.
6969
ignoreInterfaceRegexps:
7070
- ^(?i)c(?-i)ach(ing|e)
71+
72+
# ReportInternalErrors determines whether wrapcheck should report errors returned
73+
# from inside the package.
74+
reportInternalErrors: true
7175
```
7276
7377
## Usage
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
reportInternalErrors: true
2+
3+
ignoreSigs:
4+
- .Errorf(
5+
- errors.New(
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
)
8+
9+
func main() {
10+
do()
11+
}
12+
13+
func do() error {
14+
// Internal function
15+
if err := fn(); err != nil {
16+
return err // want `error should be unwrapped`
17+
}
18+
if err := fn(); err != nil {
19+
return fmt.Errorf("wrap: %w", err)
20+
}
21+
22+
// Internal struct method
23+
ss := someStruct{}
24+
if err := ss.someMethod(); err != nil {
25+
return err // want `error should be unwrapped`
26+
}
27+
if err := ss.someMethod(); err != nil {
28+
return fmt.Errorf("wrap: %w", err)
29+
}
30+
31+
// External function
32+
if _, err := json.Marshal(struct{}{}); err != nil {
33+
return err // want `error should be unwrapped`
34+
}
35+
if _, err := json.Marshal(struct{}{}); err != nil {
36+
return fmt.Errorf("wrap: %w", err)
37+
}
38+
39+
var si someInterface = &someInterfaceImpl{}
40+
if err := si.SomeMethod(); err != nil {
41+
return err // want `error should be unwrapped`
42+
}
43+
if err := si.SomeMethod(); err != nil {
44+
return fmt.Errorf("wrap: %w", err)
45+
}
46+
47+
return nil
48+
}
49+
50+
func fn() error {
51+
return errors.New("error")
52+
}
53+
54+
type someStruct struct{}
55+
56+
func (s *someStruct) someMethod() error {
57+
return errors.New("error")
58+
}
59+
60+
type someInterface interface {
61+
SomeMethod() error
62+
}
63+
64+
type someInterfaceImpl struct {
65+
someInterface
66+
}

wrapcheck/wrapcheck.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ type WrapcheckConfig struct {
8383
// returned from any function whose call is defined on a interface named 'Transactor'
8484
// or 'Transaction' due to the name matching the regular expression `Transac(tor|tion)`.
8585
IgnoreInterfaceRegexps []string `mapstructure:"ignoreInterfaceRegexps" yaml:"ignoreInterfaceRegexps"`
86+
87+
// ReportInternalErrors determines whether wrapcheck should report errors returned
88+
// from inside the package.
89+
ReportInternalErrors bool `mapstructure:"reportInternalErrors" yaml:"reportInternalErrors"`
8690
}
8791

8892
func NewDefaultConfig() WrapcheckConfig {
@@ -273,6 +277,16 @@ func reportUnwrapped(
273277
pkgGlobs []glob.Glob,
274278
) {
275279

280+
if cfg.ReportInternalErrors {
281+
// Check if the call is package-internal function
282+
fnIdent, ok := call.Fun.(*ast.Ident)
283+
if ok {
284+
fnSig := pass.TypesInfo.ObjectOf(fnIdent).String()
285+
pass.Reportf(tokenPos, "error should be unwrapped: sig: %s", fnSig)
286+
return
287+
}
288+
}
289+
276290
sel, ok := call.Fun.(*ast.SelectorExpr)
277291
if !ok {
278292
return
@@ -286,6 +300,13 @@ func reportUnwrapped(
286300
return
287301
}
288302

303+
// If `ReportInternalErrors` is true, report immediately.
304+
// There is no need to check the details of the selector.
305+
if cfg.ReportInternalErrors {
306+
pass.Reportf(tokenPos, "error should be unwrapped: sig: %s", fnSig)
307+
return
308+
}
309+
289310
// Check if the underlying type of the "x" in x.y.z is an interface, as
290311
// errors returned from exported interface types should be wrapped, unless
291312
// ignored as per `ignoreInterfaceRegexps`

0 commit comments

Comments
 (0)