Skip to content

Commit d500dc5

Browse files
rawen17ldez
authored andcommitted
add nakedefer linter
1 parent d5d671f commit d500dc5

File tree

8 files changed

+153
-0
lines changed

8 files changed

+153
-0
lines changed

.golangci.reference.yml

+7
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,13 @@ linters-settings:
12201220
# The position of the argument to check.
12211221
arg-pos: 1
12221222

1223+
nakedefer:
1224+
# List of regular expressions to exclude function names from check.
1225+
exclude:
1226+
- 'os\.(Create|WriteFile|Chmod)'
1227+
- 'fmt\.Print.*'
1228+
- 'io\.Close'
1229+
12231230
nakedret:
12241231
# Make an issue if func has more lines of code than this setting, and it has naked returns.
12251232
# Default: 30

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/BurntSushi/toml v1.2.1
1212
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24
1313
github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0
14+
github.com/GaijinEntertainment/go-nakedefer v1.4.0
1415
github.com/OpenPeeDeeP/depguard v1.1.1
1516
github.com/alexkohler/prealloc v1.0.0
1617
github.com/alingse/asasalint v0.0.11

go.sum

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/linters_settings.go

+5
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ type LintersSettings struct {
180180
Maligned MalignedSettings
181181
Misspell MisspellSettings
182182
MustTag MustTagSettings
183+
Nakedefer NakedeferSettings
183184
Nakedret NakedretSettings
184185
Nestif NestifSettings
185186
NilNil NilNilSettings
@@ -547,6 +548,10 @@ type MustTagSettings struct {
547548
} `mapstructure:"functions"`
548549
}
549550

551+
type NakedeferSettings struct {
552+
Exclude []string `mapstructure:"exclude"`
553+
}
554+
550555
type NakedretSettings struct {
551556
MaxFuncLines int `mapstructure:"max-func-lines"`
552557
}

pkg/golinters/nakedefer.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package golinters
2+
3+
import (
4+
"github.com/GaijinEntertainment/go-nakedefer/pkg/analyzer"
5+
"golang.org/x/tools/go/analysis"
6+
7+
"github.com/golangci/golangci-lint/pkg/config"
8+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9+
)
10+
11+
func NewNakedefer(settings *config.NakedeferSettings) *goanalysis.Linter {
12+
var exclude []string
13+
14+
if settings != nil {
15+
exclude = settings.Exclude
16+
}
17+
18+
a, err := analyzer.NewAnalyzer(exclude)
19+
if err != nil {
20+
linterLogger.Fatalf("nakedefer configuration: %v", err)
21+
}
22+
23+
return goanalysis.NewLinter(
24+
a.Name,
25+
a.Doc,
26+
[]*analysis.Analyzer{a},
27+
nil,
28+
).WithLoadMode(goanalysis.LoadModeTypesInfo)
29+
}

pkg/lint/lintersdb/manager.go

+8
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
148148
malignedCfg *config.MalignedSettings
149149
misspellCfg *config.MisspellSettings
150150
musttagCfg *config.MustTagSettings
151+
nakedeferCfg *config.NakedeferSettings
151152
nakedretCfg *config.NakedretSettings
152153
nestifCfg *config.NestifSettings
153154
nilNilCfg *config.NilNilSettings
@@ -226,6 +227,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
226227
malignedCfg = &m.cfg.LintersSettings.Maligned
227228
misspellCfg = &m.cfg.LintersSettings.Misspell
228229
musttagCfg = &m.cfg.LintersSettings.MustTag
230+
nakedeferCfg = &m.cfg.LintersSettings.Nakedefer
229231
nakedretCfg = &m.cfg.LintersSettings.Nakedret
230232
nestifCfg = &m.cfg.LintersSettings.Nestif
231233
nilNilCfg = &m.cfg.LintersSettings.NilNil
@@ -645,6 +647,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
645647
WithPresets(linter.PresetStyle, linter.PresetBugs).
646648
WithURL("https://github.com/junk1tm/musttag"),
647649

650+
linter.NewConfig(golinters.NewNakedefer(nakedeferCfg)).
651+
WithSince("v1.51.0").
652+
WithPresets(linter.PresetStyle).
653+
WithLoadForGoAnalysis().
654+
WithURL("https://github.com/GaijinEntertainment/go-nakedefer"),
655+
648656
linter.NewConfig(golinters.NewNakedret(nakedretCfg)).
649657
WithSince("v1.19.0").
650658
WithPresets(linter.PresetStyle).

test/testdata/configs/nakedefer.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
linters-settings:
2+
nakedefer:
3+
exclude: os\.(Create|WriteFile|Chmod),fmt\.Print.*,io\.Close

test/testdata/nakedefer.go

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//golangcitest:args -Enakedefer
2+
//golangcitest:config_path testdata/configs/nakedefer.yml
3+
package testdata
4+
5+
import (
6+
"bytes"
7+
"compress/zlib"
8+
"errors"
9+
"fmt"
10+
"io"
11+
"net/http"
12+
"net/http/httptest"
13+
"os"
14+
)
15+
16+
func funcNotReturnAnyType() {
17+
}
18+
19+
func funcReturnErr() error {
20+
return errors.New("some error")
21+
}
22+
23+
func funcReturnFuncAndErr() (func(), error) {
24+
return func() {
25+
}, nil
26+
}
27+
28+
func ignoreFunc() error {
29+
return errors.New("some error")
30+
}
31+
32+
func testCaseValid1() {
33+
defer funcNotReturnAnyType() // ignore
34+
35+
defer func() { //ignore
36+
funcNotReturnAnyType()
37+
}()
38+
39+
defer func() { //ignore
40+
_ = funcReturnErr()
41+
}()
42+
}
43+
44+
func testCaseInvalid1() {
45+
defer funcReturnErr() // want "deferred call should not return anything"
46+
47+
defer funcReturnFuncAndErr() // want "deferred call should not return anything"
48+
49+
defer func() error { // want "deferred call should not return anything"
50+
return nil
51+
}()
52+
53+
defer func() func() { // want "deferred call should not return anything"
54+
return func() {}
55+
}()
56+
}
57+
58+
func testCase1() {
59+
defer fmt.Errorf("some text") // want "deferred call should not return anything"
60+
61+
r := new(bytes.Buffer)
62+
defer io.LimitReader(r, 1) // want "deferred call should not return anything"
63+
64+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
65+
w.WriteHeader(http.StatusOK)
66+
_, _ = w.Write([]byte("DONE"))
67+
}))
68+
defer srv.Close() //ignore
69+
defer srv.CloseClientConnections() //ignore
70+
defer srv.Certificate() // want "deferred call should not return anything"
71+
}
72+
73+
func testCaseExclude1() {
74+
// exclude ignoreFunc
75+
defer ignoreFunc() // ignore
76+
}
77+
78+
func testCaseExclude2() {
79+
// exclude os\.(Create|WriteFile|Chmod)
80+
defer os.Create("file_test1") // ignore
81+
defer os.WriteFile("file_test2", []byte("data"), os.ModeAppend) // ignore
82+
defer os.Chmod("file_test3", os.ModeAppend) // ignore
83+
defer os.FindProcess(100500) // want "deferred call should not return anything"
84+
}
85+
86+
func testCaseExclude3() {
87+
// exclude fmt\.Print.*
88+
defer fmt.Println("e1") // ignore
89+
defer fmt.Print("e1") // ignore
90+
defer fmt.Printf("e1") // ignore
91+
defer fmt.Sprintf("some text") // want "deferred call should not return anything"
92+
}
93+
94+
func testCaseExclude4() {
95+
// exclude io\.Close
96+
rc, _ := zlib.NewReader(bytes.NewReader([]byte("111")))
97+
defer rc.Close() // ignore
98+
}

0 commit comments

Comments
 (0)