@@ -16,72 +16,84 @@ import (
16
16
"golang.org/x/tools/go/ast/inspector"
17
17
)
18
18
19
- const nakedGoPassName = "nakedgo"
20
-
21
19
// NakedGoAnalyzer prevents use of the `go` keyword.
22
- var NakedGoAnalyzer = & analysis.Analyzer {
23
- Name : nakedGoPassName ,
24
- Doc : "Prevents direct use of the 'go' keyword. Goroutines should be launched through Stopper." ,
25
- Requires : []* analysis.Analyzer {inspect .Analyzer },
26
- Run : func (pass * analysis.Pass ) (interface {}, error ) {
27
- inspect := pass .ResultOf [inspect .Analyzer ].(* inspector.Inspector )
28
- inspect .Preorder ([]ast.Node {
29
- (* ast .GoStmt )(nil ),
30
- }, func (n ast.Node ) {
31
- node := n .(* ast.GoStmt )
20
+ var NakedGoAnalyzer = NewNakedGoAnalyzer (
21
+ "nakedgo" ,
22
+ "Use of go keyword not allowed, use a Stopper instead" ,
23
+ "Prevents direct use of the 'go' keyword. Goroutines should be launched through Stopper." ,
24
+ nil ,
25
+ )
32
26
33
- const debug = false
27
+ type FilterFunc func ( pass * analysis. Pass ) bool
34
28
35
- // NB: we're not using passesutil.HasNoLintComment because it
36
- // has false negatives (i.e. comments apply to infractions that
37
- // they were clearly not intended for).
38
- //
39
- // The approach here is inspired by `analysistest.check` - the
40
- // nolint comment has to be on the same line as the *end* of the
41
- // `*GoStmt`.
42
- f := passesutil .FindContainingFile (pass , n )
43
- cm := ast .NewCommentMap (pass .Fset , node , f .Comments )
44
- var cc * ast.Comment
45
- for _ , cg := range cm [n ] {
46
- for _ , c := range cg .List {
47
- if c .Pos () < node .Go {
48
- // The current comment is "before" the `go` invocation, so it's
49
- // not relevant for silencing the lint.
50
- continue
51
- }
52
- if cc == nil || cc .Pos () > node .Go {
53
- // This comment is after, but closer to the `go` invocation than
54
- // previous candidate.
55
- cc = c
56
- if debug {
57
- fmt .Printf ("closest comment now %d-%d: %s\n " , cc .Pos (), cc .End (), cc .Text )
29
+ func NewNakedGoAnalyzer (name , message , doc string , filter FilterFunc ) * analysis.Analyzer {
30
+ return & analysis.Analyzer {
31
+ Name : name ,
32
+ Doc : doc ,
33
+ Requires : []* analysis.Analyzer {inspect .Analyzer },
34
+ Run : func (pass * analysis.Pass ) (interface {}, error ) {
35
+ if filter != nil && ! filter (pass ) {
36
+ return nil , nil
37
+ }
38
+ inspect := pass .ResultOf [inspect .Analyzer ].(* inspector.Inspector )
39
+ inspect .Preorder ([]ast.Node {
40
+ (* ast .GoStmt )(nil ),
41
+ }, func (n ast.Node ) {
42
+ node := n .(* ast.GoStmt )
43
+
44
+ const debug = false
45
+
46
+ // NB: we're not using passesutil.HasNoLintComment because it
47
+ // has false negatives (i.e. comments apply to infractions that
48
+ // they were clearly not intended for).
49
+ //
50
+ // The approach here is inspired by `analysistest.check` - the
51
+ // nolint comment has to be on the same line as the *end* of the
52
+ // `*GoStmt`.
53
+ f := passesutil .FindContainingFile (pass , n )
54
+ cm := ast .NewCommentMap (pass .Fset , node , f .Comments )
55
+ var cc * ast.Comment
56
+ for _ , cg := range cm [n ] {
57
+ for _ , c := range cg .List {
58
+ if c .Pos () < node .Go {
59
+ // The current comment is "before" the `go` invocation, so it's
60
+ // not relevant for silencing the lint.
61
+ continue
62
+ }
63
+ if cc == nil || cc .Pos () > node .Go {
64
+ // This comment is after, but closer to the `go` invocation than
65
+ // previous candidate.
66
+ cc = c
67
+ if debug {
68
+ fmt .Printf ("closest comment now %d-%d: %s\n " , cc .Pos (), cc .End (), cc .Text )
69
+ }
58
70
}
59
71
}
60
72
}
61
- }
62
- if cc != nil && strings .Contains (cc .Text , "nolint:" + nakedGoPassName ) {
63
- if debug {
64
- fmt .Printf ("GoStmt at: %d-%d\n " , n .Pos (), n .End ())
65
- fmt .Printf ("GoStmt.Go at: %d\n " , node .Go )
66
- fmt .Printf ("GoStmt.Call at: %d-%d\n " , node .Call .Pos (), node .Call .End ())
67
- }
73
+ if cc != nil && strings .Contains (cc .Text , "nolint:" + name ) {
74
+ if debug {
75
+ fmt .Printf ("GoStmt at: %d-%d\n " , n .Pos (), n .End ())
76
+ fmt .Printf ("GoStmt.Go at: %d\n " , node .Go )
77
+ fmt .Printf ("GoStmt.Call at: %d-%d\n " , node .Call .Pos (), node .Call .End ())
78
+ }
68
79
69
- goPos := pass .Fset .Position (node .End ())
70
- cmPos := pass .Fset .Position (cc .Pos ())
80
+ goPos := pass .Fset .Position (node .End ())
81
+ cmPos := pass .Fset .Position (cc .Pos ())
71
82
72
- if goPos .Line == cmPos .Line {
73
- if debug {
74
- fmt .Printf ("suppressing lint because of %d-%d: %s\n " , cc .Pos (), cc .End (), cc .Text )
83
+ if goPos .Line == cmPos .Line {
84
+ if debug {
85
+ fmt .Printf ("suppressing lint because of %d-%d: %s\n " , cc .Pos (), cc .End (), cc .Text )
86
+ }
87
+ return
75
88
}
76
- return
77
89
}
78
- }
79
90
80
- pass .Report (analysis.Diagnostic {
81
- Pos : n .Pos (),
82
- Message : "Use of go keyword not allowed, use a Stopper instead" ,
91
+ pass .Report (analysis.Diagnostic {
92
+ Pos : n .Pos (),
93
+ Message : message ,
94
+ })
83
95
})
84
- })
85
- return nil , nil
86
- },
96
+ return nil , nil
97
+ },
98
+ }
87
99
}
0 commit comments