Skip to content

Commit eeff390

Browse files
authored
Merge pull request #837 from ashanbrown/asb/nolintlint-internal
Add nolintlint linter as internal linter
2 parents 224515a + ef44e11 commit eeff390

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+765
-62
lines changed

.golangci.example.yml

+11
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,17 @@ linters-settings:
224224
simple: true
225225
range-loops: true # Report preallocation suggestions on range loops, true by default
226226
for-loops: false # Report preallocation suggestions on for loops, false by default
227+
nolintlint:
228+
# Enable to ensure that nolint directives are all used. Default is true.
229+
allow-unused: false
230+
# Disable to ensure that nolint directives don't have a leading space. Default is true.
231+
allow-leading-space: true
232+
# Exclude following linters from requiring an explanation. Default is [].
233+
allow-no-explanation: []
234+
# Enable to require an explanation after each nolint directive. Default is false.
235+
require-explanation: true
236+
# Enable to require an explanation after each nolint directive. Default is false.
237+
require-specific: true
227238
rowserrcheck:
228239
packages:
229240
- github.com/jmoiron/sqlx

.golangci.yml

+6
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ linters-settings:
5454
suggest-new: true
5555
misspell:
5656
locale: US
57+
nolintlint:
58+
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
59+
allow-unused: false # report any unused nolint directives
60+
require-explanation: false # don't require an explanation for nolint directives
61+
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
5762

5863
linters:
5964
# please, do not use `enable-all`: it's deprecated and will be removed soon.
@@ -84,6 +89,7 @@ linters:
8489
- lll
8590
- misspell
8691
- nakedret
92+
- nolintlint
8793
- rowserrcheck
8894
- scopelint
8995
- staticcheck

README.md

+20
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ maligned: Tool to detect Go structs that would take less memory if their fields
232232
misspell: Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
233233
nakedret: Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
234234
nestif: Reports deeply nested if statements [fast: true, auto-fix: false]
235+
nolintlint: Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false]
235236
prealloc: Finds slice declarations that could potentially be preallocated [fast: true, auto-fix: false]
236237
rowserrcheck: checks whether Err of rows is checked successfully [fast: true, auto-fix: false]
237238
scopelint: Scopelint checks for unpinned variables in go programs [fast: true, auto-fix: false]
@@ -498,6 +499,7 @@ golangci-lint help linters
498499
- [godot](https://github.com/tetafro/godot) - Check if comments end in a period
499500
- [testpackage](https://github.com/maratori/testpackage) - linter that makes you use a separate _test package
500501
- [nestif](https://github.com/nakabonne/nestif) - Reports deeply nested if statements
502+
- [nolintlint](https://github.com/golangci-lint/pkg/golinters/nolintlint) - Reports ill-formed or insufficient nolint directives
501503
502504
## Configuration
503505
@@ -845,6 +847,17 @@ linters-settings:
845847
simple: true
846848
range-loops: true # Report preallocation suggestions on range loops, true by default
847849
for-loops: false # Report preallocation suggestions on for loops, false by default
850+
nolintlint:
851+
# Enable to ensure that nolint directives are all used. Default is true.
852+
allow-unused: false
853+
# Disable to ensure that nolint directives don't have a leading space. Default is true.
854+
allow-leading-space: true
855+
# Exclude following linters from requiring an explanation. Default is [].
856+
allow-no-explanation: []
857+
# Enable to require an explanation after each nolint directive. Default is false.
858+
require-explanation: true
859+
# Enable to require an explanation after each nolint directive. Default is false.
860+
require-specific: true
848861
rowserrcheck:
849862
packages:
850863
- github.com/jmoiron/sqlx
@@ -1034,6 +1047,11 @@ linters-settings:
10341047
suggest-new: true
10351048
misspell:
10361049
locale: US
1050+
nolintlint:
1051+
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
1052+
allow-unused: false # report any unused nolint directives
1053+
require-explanation: false # don't require an explanation for nolint directives
1054+
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
10371055
10381056
linters:
10391057
# please, do not use `enable-all`: it's deprecated and will be removed soon.
@@ -1064,6 +1082,7 @@ linters:
10641082
- lll
10651083
- misspell
10661084
- nakedret
1085+
- nolintlint
10671086
- rowserrcheck
10681087
- scopelint
10691088
- staticcheck
@@ -1301,6 +1320,7 @@ Thanks to developers and authors of used linters:
13011320
- [tetafro](https://github.com/tetafro)
13021321
- [maratori](https://github.com/maratori)
13031322
- [nakabonne](https://github.com/nakabonne)
1323+
- [golangci-lint](https://github.com/golangci-lint)
13041324
13051325
## Changelog
13061326

pkg/commands/run.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ func (e *Executor) executeRun(_ *cobra.Command, args []string) {
441441
// to be removed when deadline is finally decommissioned
442442
func (e *Executor) setTimeoutToDeadlineIfOnlyDeadlineIsSet() {
443443
//lint:ignore SA1019 We want to promoted the deprecated config value when needed
444-
deadlineValue := e.cfg.Run.Deadline // nolint: staticcheck
444+
deadlineValue := e.cfg.Run.Deadline // nolint:staticcheck
445445
if deadlineValue != 0 && e.cfg.Run.Timeout == defaultTimeout {
446446
e.cfg.Run.Timeout = deadlineValue
447447
}

pkg/config/config.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ type LintersSettings struct {
235235
Godot GodotSettings
236236
Testpackage TestpackageSettings
237237
Nestif NestifSettings
238+
NoLintLint NoLintLintSettings
238239

239240
Custom map[string]CustomLinterSettings
240241
}
@@ -316,6 +317,14 @@ type GodotSettings struct {
316317
CheckAll bool `mapstructure:"check-all"`
317318
}
318319

320+
type NoLintLintSettings struct {
321+
RequireExplanation bool `mapstructure:"require-explanation"`
322+
AllowLeadingSpace bool `mapstructure:"allow-leading-space"`
323+
RequireSpecific bool `mapstructure:"require-specific"`
324+
AllowNoExplanation []string `mapstructure:"allow-no-explanation"`
325+
AllowUnused bool `mapstructure:"allow-unused"`
326+
}
327+
319328
type TestpackageSettings struct {
320329
SkipRegexp string `mapstructure:"skip-regexp"`
321330
}
@@ -324,7 +333,6 @@ type NestifSettings struct {
324333
MinComplexity int `mapstructure:"min-complexity"`
325334
}
326335

327-
//nolint:gomnd
328336
var defaultLintersSettings = LintersSettings{
329337
Lll: LllSettings{
330338
LineLength: 120,
@@ -363,6 +371,12 @@ var defaultLintersSettings = LintersSettings{
363371
ForceCuddleErrCheckAndAssign: false,
364372
ForceCaseTrailingWhitespaceLimit: 0,
365373
},
374+
NoLintLint: NoLintLintSettings{
375+
RequireExplanation: false,
376+
AllowLeadingSpace: true,
377+
RequireSpecific: false,
378+
AllowUnused: false,
379+
},
366380
Testpackage: TestpackageSettings{
367381
SkipRegexp: `(export|internal)_test\.go`,
368382
},

pkg/golinters/deadcode.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func NewDeadcode() *goanalysis.Linter {
2828
}
2929
res := make([]goanalysis.Issue, 0, len(issues))
3030
for _, i := range issues {
31-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
31+
res = append(res, goanalysis.NewIssue(&result.Issue{
3232
Pos: i.Pos,
3333
Text: fmt.Sprintf("%s is unused", formatCode(i.UnusedIdentName, nil)),
3434
FromLinter: linterName,

pkg/golinters/depguard.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func NewDepguard() *goanalysis.Linter {
9494
if userSuppliedMsgSuffix != "" {
9595
userSuppliedMsgSuffix = ": " + userSuppliedMsgSuffix
9696
}
97-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
97+
res = append(res, goanalysis.NewIssue(&result.Issue{
9898
Pos: i.Position,
9999
Text: fmt.Sprintf("%s %s%s", formatCode(i.PackageName, lintCtx.Cfg), msgSuffix, userSuppliedMsgSuffix),
100100
FromLinter: linterName,

pkg/golinters/dupl.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func NewDupl() *goanalysis.Linter {
5757
text := fmt.Sprintf("%d-%d lines are duplicate of %s",
5858
i.From.LineStart(), i.From.LineEnd(),
5959
formatCode(dupl, lintCtx.Cfg))
60-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
60+
res = append(res, goanalysis.NewIssue(&result.Issue{
6161
Pos: token.Position{
6262
Filename: i.From.Filename(),
6363
Line: i.From.LineStart(),

pkg/golinters/errcheck.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func NewErrcheck() *goanalysis.Linter {
5959
} else {
6060
text = "Error return value is not checked"
6161
}
62-
issues = append(issues, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
62+
issues = append(issues, goanalysis.NewIssue(&result.Issue{
6363
FromLinter: linterName,
6464
Text: text,
6565
Pos: i.Pos,

pkg/golinters/funlen.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func NewFunlen() *goanalysis.Linter {
4242

4343
res := make([]goanalysis.Issue, len(issues))
4444
for k, i := range issues {
45-
res[k] = goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
45+
res[k] = goanalysis.NewIssue(&result.Issue{
4646
Pos: token.Position{
4747
Filename: i.Pos.Filename,
4848
Line: i.Pos.Line,

pkg/golinters/goanalysis/issue.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ func NewIssue(i *result.Issue, pass *analysis.Pass) Issue {
2121
}
2222

2323
type EncodingIssue struct {
24-
FromLinter string
25-
Text string
26-
Pos token.Position
27-
LineRange *result.Range
28-
Replacement *result.Replacement
24+
FromLinter string
25+
Text string
26+
Pos token.Position
27+
LineRange *result.Range
28+
Replacement *result.Replacement
29+
ExpectNoLint bool
30+
ExpectedNoLintLinter string
2931
}

pkg/golinters/goanalysis/linter.go

+15-11
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,13 @@ func saveIssuesToCache(allPkgs []*packages.Package, pkgsFromCache map[*packages.
323323
for ind := range pkgIssues {
324324
i := &pkgIssues[ind]
325325
encodedIssues = append(encodedIssues, EncodingIssue{
326-
FromLinter: i.FromLinter,
327-
Text: i.Text,
328-
Pos: i.Pos,
329-
LineRange: i.LineRange,
330-
Replacement: i.Replacement,
326+
FromLinter: i.FromLinter,
327+
Text: i.Text,
328+
Pos: i.Pos,
329+
LineRange: i.LineRange,
330+
Replacement: i.Replacement,
331+
ExpectNoLint: i.ExpectNoLint,
332+
ExpectedNoLintLinter: i.ExpectedNoLintLinter,
331333
})
332334
}
333335

@@ -392,12 +394,14 @@ func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context,
392394
issues := make([]result.Issue, 0, len(pkgIssues))
393395
for _, i := range pkgIssues {
394396
issues = append(issues, result.Issue{
395-
FromLinter: i.FromLinter,
396-
Text: i.Text,
397-
Pos: i.Pos,
398-
LineRange: i.LineRange,
399-
Replacement: i.Replacement,
400-
Pkg: pkg,
397+
FromLinter: i.FromLinter,
398+
Text: i.Text,
399+
Pos: i.Pos,
400+
LineRange: i.LineRange,
401+
Replacement: i.Replacement,
402+
Pkg: pkg,
403+
ExpectNoLint: i.ExpectNoLint,
404+
ExpectedNoLintLinter: i.ExpectedNoLintLinter,
401405
})
402406
}
403407
cacheRes.issues = issues

pkg/golinters/goanalysis/runner.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ func (r *runner) analyze(pkgs []*packages.Package, analyzers []*analysis.Analyze
312312
debugf("There are %d initial and %d total packages", len(initialPkgs), len(loadingPackages))
313313
for _, lp := range loadingPackages {
314314
if lp.isInitial {
315-
wg.Add(1) //nolint:gomnd
315+
wg.Add(1)
316316
go func(lp *loadingPackage) {
317317
lp.analyzeRecursive(r.loadMode, loadSem)
318318
wg.Done()

pkg/golinters/gocognit.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func NewGocognit() *goanalysis.Linter {
4949
break // Break as the stats is already sorted from greatest to least
5050
}
5151

52-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
52+
res = append(res, goanalysis.NewIssue(&result.Issue{
5353
Pos: s.Pos,
5454
Text: fmt.Sprintf("cognitive complexity %d of func %s is high (> %d)",
5555
s.Complexity, formatCode(s.FuncName, lintCtx.Cfg), lintCtx.Settings().Gocognit.MinComplexity),

pkg/golinters/goconst.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func checkConstants(pass *analysis.Pass, lintCtx *linter.Context) ([]goanalysis.
7070
} else {
7171
textEnd = fmt.Sprintf(", but such constant %s already exists", formatCode(i.MatchingConst, lintCtx.Cfg))
7272
}
73-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
73+
res = append(res, goanalysis.NewIssue(&result.Issue{
7474
Pos: i.Pos,
7575
Text: textBegin + textEnd,
7676
FromLinter: goconstName,

pkg/golinters/gocyclo.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func NewGocyclo() *goanalysis.Linter {
4949
break // Break as the stats is already sorted from greatest to least
5050
}
5151

52-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
52+
res = append(res, goanalysis.NewIssue(&result.Issue{
5353
Pos: s.Pos,
5454
Text: fmt.Sprintf("cyclomatic complexity %d of func %s is high (> %d)",
5555
s.Complexity, formatCode(s.FuncName, lintCtx.Cfg), lintCtx.Settings().Gocyclo.MinComplexity),

pkg/golinters/godox.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func NewGodox() *goanalysis.Linter {
4141

4242
res := make([]goanalysis.Issue, len(issues))
4343
for k, i := range issues {
44-
res[k] = goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
44+
res[k] = goanalysis.NewIssue(&result.Issue{
4545
Pos: token.Position{
4646
Filename: i.Pos.Filename,
4747
Line: i.Pos.Line,

pkg/golinters/gofmt_common.go

-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ func (p *hunkChangesParser) parseDiffLines(h *diffpkg.Hunk) {
5959

6060
lineStr := string(line)
6161

62-
//nolint:gocritic
6362
if strings.HasPrefix(lineStr, "-") {
6463
dl.typ = diffLineDeleted
6564
dl.data = strings.TrimPrefix(lineStr, "-")

pkg/golinters/gomodguard.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func NewGomodguard() *goanalysis.Linter {
7373
defer mu.Unlock()
7474

7575
for _, err := range gomodguardErrors {
76-
issues = append(issues, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
76+
issues = append(issues, goanalysis.NewIssue(&result.Issue{
7777
FromLinter: gomodguardName,
7878
Pos: err.Position,
7979
Text: err.Reason,

pkg/golinters/gosec.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func NewGosec() *goanalysis.Linter {
7373
continue
7474
}
7575

76-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
76+
res = append(res, goanalysis.NewIssue(&result.Issue{
7777
Pos: token.Position{
7878
Filename: i.File,
7979
Line: line,

pkg/golinters/ineffassign.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func NewIneffassign() *goanalysis.Linter {
4242

4343
res := make([]goanalysis.Issue, 0, len(issues))
4444
for _, i := range issues {
45-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
45+
res = append(res, goanalysis.NewIssue(&result.Issue{
4646
Pos: i.Pos,
4747
Text: fmt.Sprintf("ineffectual assignment to %s", formatCode(i.IdentName, lintCtx.Cfg)),
4848
FromLinter: ineffassignName,

pkg/golinters/interfacer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func NewInterfacer() *goanalysis.Linter {
4848
res := make([]goanalysis.Issue, 0, len(issues))
4949
for _, i := range issues {
5050
pos := pass.Fset.Position(i.Pos())
51-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
51+
res = append(res, goanalysis.NewIssue(&result.Issue{
5252
Pos: pos,
5353
Text: i.Message(),
5454
FromLinter: interfacerName,

pkg/golinters/maligned.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func NewMaligned() *goanalysis.Linter {
4040
if lintCtx.Settings().Maligned.SuggestNewOrder {
4141
text += fmt.Sprintf(":\n%s", formatCodeBlock(i.NewStructDef, lintCtx.Cfg))
4242
}
43-
issues = append(issues, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
43+
issues = append(issues, goanalysis.NewIssue(&result.Issue{
4444
Pos: i.Pos,
4545
Text: text,
4646
FromLinter: linterName,

pkg/golinters/nestif.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func NewNestif() *goanalysis.Linter {
4646

4747
res := make([]goanalysis.Issue, 0, len(issues))
4848
for _, i := range issues {
49-
res = append(res, goanalysis.NewIssue(&result.Issue{ //nolint:scopelint
49+
res = append(res, goanalysis.NewIssue(&result.Issue{
5050
Pos: i.Pos,
5151
Text: i.Message,
5252
FromLinter: nestifName,

0 commit comments

Comments
 (0)