Skip to content

Commit 7d51954

Browse files
committed
fix #199: support gochecknoinits, gochecknoglobals
Add 2 new linters
1 parent a57bc83 commit 7d51954

File tree

9 files changed

+209
-0
lines changed

9 files changed

+209
-0
lines changed

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ linters:
3131
- maligned
3232
- prealloc
3333
- gosec
34+
- gochecknoglobals

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ nakedret: Finds naked returns in functions greater than a specified function len
201201
prealloc: Finds slice declarations that could potentially be preallocated [fast: true]
202202
scopelint: Scopelint checks for unpinned variables in go programs [fast: true]
203203
gocritic: The most opinionated Go source code linter [fast: true]
204+
gochecknoinits: Checks that no init functions are present in Go code [fast: true]
205+
gochecknoglobals: Checks that no globals are present in Go code [fast: true]
204206
```
205207
206208
Pass `-E/--enable` to enable linter and `-D/--disable` to disable:
@@ -402,6 +404,8 @@ golangci-lint help linters
402404
- [prealloc](https://github.com/alexkohler/prealloc) - Finds slice declarations that could potentially be preallocated
403405
- [scopelint](https://github.com/kyoh86/scopelint) - Scopelint checks for unpinned variables in go programs
404406
- [gocritic](https://github.com/go-critic/go-critic) - The most opinionated Go source code linter
407+
- [gochecknoinits](https://github.com/leighmcculloch/gochecknoinits) - Checks that no init functions are present in Go code
408+
- [gochecknoglobals](https://github.com/leighmcculloch/gochecknoglobals) - Checks that no globals are present in Go code
405409
406410
## Configuration
407411
@@ -745,6 +749,7 @@ linters:
745749
- maligned
746750
- prealloc
747751
- gosec
752+
- gochecknoglobals
748753
```
749754
750755
## False Positives
@@ -828,6 +833,7 @@ Thanks to developers and authors of used linters:
828833
- [alexkohler](https://github.com/alexkohler)
829834
- [kyoh86](https://github.com/kyoh86)
830835
- [go-critic](https://github.com/go-critic)
836+
- [leighmcculloch](https://github.com/leighmcculloch)
831837
832838
## Changelog
833839

pkg/golinters/gochecknoglobals.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package golinters
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"go/ast"
7+
"go/token"
8+
"strings"
9+
10+
"github.com/golangci/golangci-lint/pkg/lint/linter"
11+
"github.com/golangci/golangci-lint/pkg/result"
12+
)
13+
14+
type Gochecknoglobals struct{}
15+
16+
func (Gochecknoglobals) Name() string {
17+
return "gochecknoglobals"
18+
}
19+
20+
func (Gochecknoglobals) Desc() string {
21+
return "Checks that no globals are present in Go code"
22+
}
23+
24+
func (lint Gochecknoglobals) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
25+
var res []result.Issue
26+
for _, f := range lintCtx.ASTCache.GetAllValidFiles() {
27+
res = append(res, lint.checkFile(f.F, f.Fset)...)
28+
}
29+
30+
return res, nil
31+
}
32+
33+
func (lint Gochecknoglobals) checkFile(f *ast.File, fset *token.FileSet) []result.Issue {
34+
var res []result.Issue
35+
for _, decl := range f.Decls {
36+
genDecl, ok := decl.(*ast.GenDecl)
37+
if !ok {
38+
continue
39+
}
40+
if genDecl.Tok != token.VAR {
41+
continue
42+
}
43+
44+
for _, spec := range genDecl.Specs {
45+
valueSpec := spec.(*ast.ValueSpec)
46+
for _, vn := range valueSpec.Names {
47+
if isWhitelisted(vn) {
48+
continue
49+
}
50+
51+
res = append(res, result.Issue{
52+
Pos: fset.Position(genDecl.TokPos),
53+
Text: fmt.Sprintf("%s is a global variable", formatCode(vn.Name, nil)),
54+
FromLinter: lint.Name(),
55+
})
56+
}
57+
}
58+
}
59+
60+
return res
61+
}
62+
63+
func isWhitelisted(i *ast.Ident) bool {
64+
return i.Name == "_" || looksLikeError(i)
65+
}
66+
67+
// looksLikeError returns true if the AST identifier starts
68+
// with 'err' or 'Err', or false otherwise.
69+
//
70+
// TODO: https://github.com/leighmcculloch/gochecknoglobals/issues/5
71+
func looksLikeError(i *ast.Ident) bool {
72+
prefix := "err"
73+
if i.IsExported() {
74+
prefix = "Err"
75+
}
76+
return strings.HasPrefix(i.Name, prefix)
77+
}

pkg/golinters/gochecknoinits.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package golinters
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"go/ast"
7+
"go/token"
8+
9+
"github.com/golangci/golangci-lint/pkg/lint/linter"
10+
"github.com/golangci/golangci-lint/pkg/result"
11+
)
12+
13+
type Gochecknoinits struct{}
14+
15+
func (Gochecknoinits) Name() string {
16+
return "gochecknoinits"
17+
}
18+
19+
func (Gochecknoinits) Desc() string {
20+
return "Checks that no init functions are present in Go code"
21+
}
22+
23+
func (lint Gochecknoinits) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
24+
var res []result.Issue
25+
for _, f := range lintCtx.ASTCache.GetAllValidFiles() {
26+
res = append(res, lint.checkFile(f.F, f.Fset)...)
27+
}
28+
29+
return res, nil
30+
}
31+
32+
func (lint Gochecknoinits) checkFile(f *ast.File, fset *token.FileSet) []result.Issue {
33+
var res []result.Issue
34+
for _, decl := range f.Decls {
35+
funcDecl, ok := decl.(*ast.FuncDecl)
36+
if !ok {
37+
continue
38+
}
39+
40+
name := funcDecl.Name.Name
41+
if name == "init" && funcDecl.Recv.NumFields() == 0 {
42+
res = append(res, result.Issue{
43+
Pos: fset.Position(funcDecl.Pos()),
44+
Text: fmt.Sprintf("don't use %s function", formatCode(name, nil)),
45+
FromLinter: lint.Name(),
46+
})
47+
}
48+
}
49+
50+
return res
51+
}

pkg/lint/lintersdb/manager.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,14 @@ func (Manager) GetAllSupportedLinterConfigs() []linter.Config {
196196
WithSpeed(5).
197197
WithTypeInfo().
198198
WithURL("https://github.com/go-critic/go-critic"),
199+
linter.NewConfig(golinters.Gochecknoinits{}).
200+
WithPresets(linter.PresetStyle).
201+
WithSpeed(10).
202+
WithURL("https://github.com/leighmcculloch/gochecknoinits"),
203+
linter.NewConfig(golinters.Gochecknoglobals{}).
204+
WithPresets(linter.PresetStyle).
205+
WithSpeed(10).
206+
WithURL("https://github.com/leighmcculloch/gochecknoglobals"),
199207
}
200208

201209
isLocalRun := os.Getenv("GOLANGCI_COM_RUN") == ""

test/testdata/gochecknoglobals.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// args: -Egochecknoglobals
2+
package testdata
3+
4+
import (
5+
"errors"
6+
"fmt"
7+
)
8+
9+
var noGlobalsVar int // ERROR "`noGlobalsVar` is a global variable"
10+
var ErrSomeType = errors.New("test that global erorrs aren't warned")
11+
12+
func NoGlobals() {
13+
fmt.Print(noGlobalsVar)
14+
}

test/testdata/gochecknoinits.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// args: -Egochecknoinits
2+
package testdata
3+
4+
import "fmt"
5+
6+
func init() { // ERROR "don't use `init` function"
7+
fmt.Println()
8+
}
9+
10+
func Init() {}

third_party/gochecknoglobals/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 Leigh McCulloch
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

third_party/gochecknoinits/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 Leigh McCulloch
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)