Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add nakedefer linter #3282

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions .golangci.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,14 @@ linters-settings:
# The position of the argument to check.
arg-pos: 1

nakedefer:
# List of regular expressions to exclude function names from check.
# Default: []
exclude:
- 'os\.(Create|WriteFile|Chmod)'
- 'fmt\.Print.*'
- 'io\.Close'

nakedret:
# Make an issue if func has more lines of code than this setting, and it has naked returns.
# Default: 30
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/BurntSushi/toml v1.2.1
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24
github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0
github.com/GaijinEntertainment/go-nakedefer v1.4.0
github.com/OpenPeeDeeP/depguard v1.1.1
github.com/alexkohler/prealloc v1.0.0
github.com/alingse/asasalint v0.0.11
Expand Down
2 changes: 2 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/config/linters_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ type LintersSettings struct {
Maligned MalignedSettings
Misspell MisspellSettings
MustTag MustTagSettings
Nakedefer NakedeferSettings
Nakedret NakedretSettings
Nestif NestifSettings
NilNil NilNilSettings
Expand Down Expand Up @@ -548,6 +549,10 @@ type MustTagSettings struct {
} `mapstructure:"functions"`
}

type NakedeferSettings struct {
Exclude []string `mapstructure:"exclude"`
}

type NakedretSettings struct {
MaxFuncLines int `mapstructure:"max-func-lines"`
}
Expand Down
29 changes: 29 additions & 0 deletions pkg/golinters/nakedefer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package golinters

import (
"github.com/GaijinEntertainment/go-nakedefer/pkg/analyzer"
"golang.org/x/tools/go/analysis"

"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
)

func NewNakedefer(settings *config.NakedeferSettings) *goanalysis.Linter {
var exclude []string

if settings != nil {
exclude = settings.Exclude
}

a, err := analyzer.NewAnalyzer(exclude)
if err != nil {
linterLogger.Fatalf("nakedefer configuration: %v", err)
}

return goanalysis.NewLinter(
a.Name,
a.Doc,
[]*analysis.Analyzer{a},
nil,
).WithLoadMode(goanalysis.LoadModeTypesInfo)
}
8 changes: 8 additions & 0 deletions pkg/lint/lintersdb/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
malignedCfg *config.MalignedSettings
misspellCfg *config.MisspellSettings
musttagCfg *config.MustTagSettings
nakedeferCfg *config.NakedeferSettings
nakedretCfg *config.NakedretSettings
nestifCfg *config.NestifSettings
nilNilCfg *config.NilNilSettings
Expand Down Expand Up @@ -226,6 +227,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
malignedCfg = &m.cfg.LintersSettings.Maligned
misspellCfg = &m.cfg.LintersSettings.Misspell
musttagCfg = &m.cfg.LintersSettings.MustTag
nakedeferCfg = &m.cfg.LintersSettings.Nakedefer
nakedretCfg = &m.cfg.LintersSettings.Nakedret
nestifCfg = &m.cfg.LintersSettings.Nestif
nilNilCfg = &m.cfg.LintersSettings.NilNil
Expand Down Expand Up @@ -645,6 +647,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithPresets(linter.PresetStyle, linter.PresetBugs).
WithURL("https://github.com/junk1tm/musttag"),

linter.NewConfig(golinters.NewNakedefer(nakedeferCfg)).
WithSince("v1.52.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/GaijinEntertainment/go-nakedefer"),

linter.NewConfig(golinters.NewNakedret(nakedretCfg)).
WithSince("v1.19.0").
WithPresets(linter.PresetStyle).
Expand Down
7 changes: 7 additions & 0 deletions test/testdata/configs/nakedefer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
linters-settings:
nakedefer:
exclude:
- os\.(Create|WriteFile|Chmod)
- fmt\.Print.*
- io\.Close
- ignoreFunc
98 changes: 98 additions & 0 deletions test/testdata/nakedefer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//golangcitest:args -Enakedefer
//golangcitest:config_path testdata/configs/nakedefer.yml
package testdata

import (
"bytes"
"compress/zlib"
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
)

func funcNotReturnAnyType() {
}

func funcReturnErr() error {
return errors.New("some error")
}

func funcReturnFuncAndErr() (func(), error) {
return func() {
}, nil
}

func ignoreFunc() error {
return errors.New("some error")
}

func testCaseValid1() {
defer funcNotReturnAnyType() // ignore

defer func() { // ignore
funcNotReturnAnyType()
}()

defer func() { // ignore
_ = funcReturnErr()
}()
}

func testCaseInvalid1() {
defer funcReturnErr() // want "deferred call should not return anything"

defer funcReturnFuncAndErr() // want "deferred call should not return anything"

defer func() error { // want "deferred call should not return anything"
return nil
}()

defer func() func() { // want "deferred call should not return anything"
return func() {}
}()
}

func testCase1() {
defer fmt.Errorf("some text") // want "deferred call should not return anything"

r := new(bytes.Buffer)
defer io.LimitReader(r, 1) // want "deferred call should not return anything"

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("DONE"))
}))
defer srv.Close() // ignore
defer srv.CloseClientConnections() // ignore
defer srv.Certificate() // want "deferred call should not return anything"
}

func testCaseExclude1() {
// exclude ignoreFunc
defer ignoreFunc() // ignore
}

func testCaseExclude2() {
// exclude os\.(Create|WriteFile|Chmod)
defer os.Create("file_test1") // ignore
defer os.WriteFile("file_test2", []byte("data"), os.ModeAppend) // ignore
defer os.Chmod("file_test3", os.ModeAppend) // ignore
defer os.FindProcess(100500) // want "deferred call should not return anything"
}

func testCaseExclude3() {
// exclude fmt\.Print.*
defer fmt.Println("e1") // ignore
defer fmt.Print("e1") // ignore
defer fmt.Printf("e1") // ignore
defer fmt.Sprintf("some text") // want "deferred call should not return anything"
}

func testCaseExclude4() {
// exclude io\.Close
rc, _ := zlib.NewReader(bytes.NewReader([]byte("111")))
defer rc.Close() // ignore
}