Skip to content

Commit f44d6b5

Browse files
committed
update linter implementation
1 parent d98c08b commit f44d6b5

File tree

6 files changed

+285
-7
lines changed

6 files changed

+285
-7
lines changed

.golangci.reference.yml

+5
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,11 @@ linters-settings:
11541154
# Default: false
11551155
require-specific: true
11561156

1157+
nonamedreturns:
1158+
# Do not complain about named error, if it is assigned inside defer.
1159+
# Default: false
1160+
allow-error-in-defer: true
1161+
11571162
paralleltest:
11581163
# Ignore missing calls to `t.Parallel()` and only report incorrect uses of it.
11591164
# Default: false

pkg/config/linters_settings.go

+4
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ type LintersSettings struct {
158158
NilNil NilNilSettings
159159
Nlreturn NlreturnSettings
160160
NoLintLint NoLintLintSettings
161+
NoNamedReturns NoNamedReturnsSettings
161162
ParallelTest ParallelTestSettings
162163
Prealloc PreallocSettings
163164
Predeclared PredeclaredSettings
@@ -484,6 +485,9 @@ type NoLintLintSettings struct {
484485
AllowUnused bool `mapstructure:"allow-unused"`
485486
}
486487

488+
type NoNamedReturnsSettings struct {
489+
AllowErrorInDefer bool `mapstructure:"allow-error-in-defer"`
490+
}
487491
type ParallelTestSettings struct {
488492
IgnoreMissing bool `mapstructure:"ignore-missing"`
489493
}

pkg/golinters/nonamedreturns.go

+17-5
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,26 @@ import (
44
"github.com/firefart/nonamedreturns/analyzer"
55
"golang.org/x/tools/go/analysis"
66

7+
"github.com/golangci/golangci-lint/pkg/config"
78
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
89
)
910

10-
func NewNoNamedReturns() *goanalysis.Linter {
11+
func NewNoNamedReturns(settings *config.NoNamedReturnsSettings) *goanalysis.Linter {
12+
a := analyzer.Analyzer
13+
14+
var cfg map[string]map[string]interface{}
15+
if settings != nil {
16+
cfg = map[string]map[string]interface{}{
17+
a.Name: {
18+
analyzer.FlagAllowErrorInDefer: settings.AllowErrorInDefer,
19+
},
20+
}
21+
}
22+
1123
return goanalysis.NewLinter(
12-
"nonamedreturns",
13-
"Reports all named returns",
14-
[]*analysis.Analyzer{analyzer.Analyzer},
15-
nil,
24+
a.Name,
25+
a.Doc,
26+
[]*analysis.Analyzer{a},
27+
cfg,
1628
).WithLoadMode(goanalysis.LoadModeSyntax)
1729
}

pkg/lint/lintersdb/manager.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
147147
nilNilCfg *config.NilNilSettings
148148
nlreturnCfg *config.NlreturnSettings
149149
noLintLintCfg *config.NoLintLintSettings
150+
noNamedReturnsCfg *config.NoNamedReturnsSettings
150151
parallelTestCfg *config.ParallelTestSettings
151152
preallocCfg *config.PreallocSettings
152153
predeclaredCfg *config.PredeclaredSettings
@@ -216,6 +217,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
216217
nilNilCfg = &m.cfg.LintersSettings.NilNil
217218
nlreturnCfg = &m.cfg.LintersSettings.Nlreturn
218219
noLintLintCfg = &m.cfg.LintersSettings.NoLintLint
220+
noNamedReturnsCfg = &m.cfg.LintersSettings.NoNamedReturns
219221
preallocCfg = &m.cfg.LintersSettings.Prealloc
220222
parallelTestCfg = &m.cfg.LintersSettings.ParallelTest
221223
predeclaredCfg = &m.cfg.LintersSettings.Predeclared
@@ -623,7 +625,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
623625
WithURL("https://github.com/sonatard/noctx").
624626
WithNoopFallback(m.cfg),
625627

626-
linter.NewConfig(golinters.NewNoNamedReturns()).
628+
linter.NewConfig(golinters.NewNoNamedReturns(noNamedReturnsCfg)).
627629
WithSince("v1.46.0").
628630
WithPresets(linter.PresetStyle).
629631
WithURL("https://github.com/firefart/nonamedreturns"),

test/testdata/nonamedreturns.go

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//args: -Enonamedreturns
1+
// args: -Enonamedreturns
22
package testdata
33

44
import "fmt"
@@ -24,6 +24,17 @@ var e = func() (err error) { // ERROR `named return "err" with type "error" foun
2424
return
2525
}
2626

27+
var e2 = func() (_ error) {
28+
return
29+
}
30+
31+
func deferWithError() (err error) { // ERROR `named return "err" with type "error" found`
32+
defer func() {
33+
err = nil // use flag to allow this
34+
}()
35+
return
36+
}
37+
2738
var (
2839
f = func() {
2940
return
@@ -37,6 +48,10 @@ var (
3748
err = nil
3849
return
3950
}
51+
52+
h2 = func() (_ error) {
53+
return
54+
}
4055
)
4156

4257
// this should not match as the implementation does not need named parameters (see below)
@@ -50,11 +65,24 @@ func funcDefintionImpl2(arg1, arg2 interface{}) (num int, err error) { // ERROR
5065
return 0, nil
5166
}
5267

68+
func funcDefintionImpl3(arg1, arg2 interface{}) (num int, _ error) { // ERROR `named return "num" with type "int" found`
69+
return 0, nil
70+
}
71+
72+
func funcDefintionImpl4(arg1, arg2 interface{}) (_ int, _ error) {
73+
return 0, nil
74+
}
75+
5376
var funcVar = func() (msg string) { // ERROR `named return "msg" with type "string" found`
5477
msg = "c"
5578
return msg
5679
}
5780

81+
var funcVar2 = func() (_ string) {
82+
msg := "c"
83+
return msg
84+
}
85+
5886
func test() {
5987
a := funcVar()
6088
_ = a
@@ -92,3 +120,5 @@ func myLog(format string, args ...interface{}) {
92120
type obj struct{}
93121

94122
func (o *obj) func1() (err error) { return nil } // ERROR `named return "err" with type "error" found`
123+
124+
func (o *obj) func2() (_ error) { return nil }
+225
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
// args: -Enonamedreturns
2+
// config: linters-settings.nonamedreturns.allow-error-in-defer=true
3+
package testdata
4+
5+
func simple() (err error) {
6+
defer func() {
7+
err = nil
8+
}()
9+
return
10+
}
11+
12+
func twoReturnParams() (i int, err error) { // ERROR `named return "i" with type "int" found`
13+
defer func() {
14+
i = 0
15+
err = nil
16+
}()
17+
return
18+
}
19+
20+
func allUnderscoresExceptError() (_ int, err error) {
21+
defer func() {
22+
err = nil
23+
}()
24+
return
25+
}
26+
27+
func customName() (myName error) {
28+
defer func() {
29+
myName = nil
30+
}()
31+
return
32+
}
33+
34+
func errorIsNoAssigned() (err error) { // ERROR `named return "err" with type "error" found`
35+
defer func() {
36+
_ = err
37+
processError(err)
38+
if err == nil {
39+
}
40+
switch err {
41+
case nil:
42+
default:
43+
}
44+
}()
45+
return
46+
}
47+
48+
func shadowVariable() (err error) {
49+
defer func() {
50+
err := 123 // linter doesn't understand that this is different variable (even if different type) (yet?)
51+
_ = err
52+
}()
53+
return
54+
}
55+
56+
func shadowVariable2() (err error) {
57+
defer func() {
58+
a, err := doSomething() // linter doesn't understand that this is different variable (yet?)
59+
_ = a
60+
_ = err
61+
}()
62+
return
63+
}
64+
65+
type myError = error // linter doesn't understand that this is the same type (yet?)
66+
67+
func customType() (err myError) { // ERROR `named return "err" with type "myError" found`
68+
defer func() {
69+
err = nil
70+
}()
71+
return
72+
}
73+
74+
func notTheLast() (err error, _ int) {
75+
defer func() {
76+
err = nil
77+
}()
78+
return
79+
}
80+
81+
func twoErrorsCombined() (err1, err2 error) {
82+
defer func() {
83+
err1 = nil
84+
err2 = nil
85+
}()
86+
return
87+
}
88+
89+
func twoErrorsSeparated() (err1 error, err2 error) {
90+
defer func() {
91+
err1 = nil
92+
err2 = nil
93+
}()
94+
return
95+
}
96+
97+
func errorSlice() (err []error) { // ERROR `named return "err" with type "\[\]error" found`
98+
defer func() {
99+
err = nil
100+
}()
101+
return
102+
}
103+
104+
func deferWithVariable() (err error) { // ERROR `named return "err" with type "error" found`
105+
f := func() {
106+
err = nil
107+
}
108+
defer f() // linter can't catch closure passed via variable (yet?)
109+
return
110+
}
111+
112+
func uberMultierr() (err error) { // ERROR `named return "err" with type "error" found`
113+
defer func() {
114+
multierrAppendInto(&err, nil) // linter doesn't allow it (yet?)
115+
}()
116+
return
117+
}
118+
119+
func deferInDefer() (err error) {
120+
defer func() {
121+
defer func() {
122+
err = nil
123+
}()
124+
}()
125+
return
126+
}
127+
128+
func twoDefers() (err error) {
129+
defer func() {}()
130+
defer func() {
131+
err = nil
132+
}()
133+
return
134+
}
135+
136+
func callFunction() (err error) {
137+
defer func() {
138+
_, err = doSomething()
139+
}()
140+
return
141+
}
142+
143+
func callFunction2() (err error) {
144+
defer func() {
145+
var a int
146+
a, err = doSomething()
147+
_ = a
148+
}()
149+
return
150+
}
151+
152+
func deepInside() (err error) {
153+
if true {
154+
switch true {
155+
case false:
156+
for i := 0; i < 10; i++ {
157+
go func() {
158+
select {
159+
default:
160+
defer func() {
161+
if true {
162+
switch true {
163+
case false:
164+
for j := 0; j < 10; j++ {
165+
go func() {
166+
select {
167+
default:
168+
err = nil
169+
}
170+
}()
171+
}
172+
}
173+
}
174+
}()
175+
}
176+
}()
177+
}
178+
}
179+
}
180+
return
181+
}
182+
183+
var goodFuncLiteral = func() (err error) {
184+
defer func() {
185+
err = nil
186+
}()
187+
return
188+
}
189+
190+
var badFuncLiteral = func() (err error) { // ERROR `named return "err" with type "error" found`
191+
defer func() {
192+
_ = err
193+
}()
194+
return
195+
}
196+
197+
func funcLiteralInsideFunc() error {
198+
do := func() (err error) {
199+
defer func() {
200+
err = nil
201+
}()
202+
return
203+
}
204+
return do()
205+
}
206+
207+
type x struct{}
208+
209+
func (x) goodMethod() (err error) {
210+
defer func() {
211+
err = nil
212+
}()
213+
return
214+
}
215+
216+
func (x) badMethod() (err error) { // ERROR `named return "err" with type "error" found`
217+
defer func() {
218+
_ = err
219+
}()
220+
return
221+
}
222+
223+
func processError(error) {}
224+
func doSomething() (int, error) { return 10, nil }
225+
func multierrAppendInto(*error, error) bool { return false } // https://pkg.go.dev/go.uber.org/multierr#AppendInto

0 commit comments

Comments
 (0)