@@ -2,15 +2,12 @@ package recovergoroutine
2
2
3
3
import (
4
4
"flag"
5
- "fmt"
6
5
"go/ast"
7
- "go/parser"
8
- "go/types"
9
- "reflect"
10
-
11
6
"golang.org/x/tools/go/analysis"
12
7
)
13
8
9
+ type message string
10
+
14
11
var customRecover string
15
12
16
13
func NewAnalyzer () * analysis.Analyzer {
@@ -25,8 +22,7 @@ func NewAnalyzer() *analysis.Analyzer {
25
22
& customRecover ,
26
23
"recover" ,
27
24
"" ,
28
- "It is difficult to determine if a CustomRecover function declared in another package is valid," +
29
- " so this option can be used to resolve it." ,
25
+ "You can use this option when you want to call a method defined in a struct or use CustomRecover declared in an external package." ,
30
26
)
31
27
32
28
return analyzer
@@ -41,12 +37,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
41
37
return true
42
38
}
43
39
44
- ok , err := safeGoStmt (goStmt , pass )
45
- if err != nil {
46
- runErr = err
47
- return false
48
- }
49
-
40
+ ok , msg := safeGoStmt (goStmt )
50
41
if ok {
51
42
return true
52
43
}
@@ -55,7 +46,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
55
46
Pos : goStmt .Pos (),
56
47
End : 0 ,
57
48
Category : "goroutine" ,
58
- Message : "goroutine must have recover" ,
49
+ Message : string ( msg ) ,
59
50
})
60
51
61
52
return false
@@ -65,43 +56,28 @@ func run(pass *analysis.Pass) (interface{}, error) {
65
56
return nil , runErr
66
57
}
67
58
68
- func safeGoStmt (goStmt * ast.GoStmt , pass * analysis. Pass ) (bool , error ) {
59
+ func safeGoStmt (goStmt * ast.GoStmt ) (bool , message ) {
69
60
fn := goStmt .Call
70
61
switch fun := fn .Fun .(type ) {
71
- case * ast.SelectorExpr :
72
- return safeSelectorExpr (fun , pass , safeFunc )
73
62
case * ast.FuncLit :
74
- return safeFunc (fun , pass )
75
- case * ast.Ident :
76
- if fun .Obj == nil {
77
- return false , nil
78
- }
79
-
80
- funcDecl , ok := fun .Obj .Decl .(* ast.FuncDecl )
81
- if ! ok {
82
- return false , nil
63
+ if ! safeFunc (fun ) {
64
+ return false , "goroutine must have recover"
83
65
}
84
-
85
- return safeFunc (funcDecl , pass )
66
+ return true , ""
86
67
}
87
68
88
- return false , fmt . Errorf ( "unexpected goroutine function type: %v" , reflect . TypeOf ( fn . Fun ). String ())
69
+ return false , "use function literals when using goroutines"
89
70
}
90
71
91
- func safeFunc (node ast.Node , pass * analysis. Pass ) ( bool , error ) {
72
+ func safeFunc (node ast.Node ) bool {
92
73
result := false
93
- var err error
94
74
ast .Inspect (node , func (node ast.Node ) bool {
95
75
deferStmt , ok := node .(* ast.DeferStmt )
96
76
if ! ok {
97
77
return true
98
78
}
99
79
100
- ok , err = hasRecover (deferStmt .Call , pass )
101
- if err != nil {
102
- return false
103
- }
104
-
80
+ ok = hasRecover (deferStmt .Call )
105
81
if ok {
106
82
result = true
107
83
return false
@@ -110,12 +86,11 @@ func safeFunc(node ast.Node, pass *analysis.Pass) (bool, error) {
110
86
return ! result
111
87
})
112
88
113
- return result , err
89
+ return result
114
90
}
115
91
116
- func hasRecover (expr ast.Node , pass * analysis. Pass ) ( bool , error ) {
92
+ func hasRecover (expr ast.Node ) bool {
117
93
var result bool
118
- var err error
119
94
ast .Inspect (expr , func (node ast.Node ) bool {
120
95
switch n := node .(type ) {
121
96
case * ast.CallExpr :
@@ -128,69 +103,15 @@ func hasRecover(expr ast.Node, pass *analysis.Pass) (bool, error) {
128
103
return true
129
104
}
130
105
131
- var ok bool
132
- ok , err = safeSelectorExpr (n , pass , hasRecover )
133
- if err != nil {
134
- return false
135
- }
136
-
137
- if ok || n .Sel .Name == customRecover {
106
+ if n .Sel .Name == customRecover {
138
107
result = true
139
108
return false
140
109
}
141
110
}
142
111
return true
143
112
})
144
113
145
- return result , err
146
- }
147
-
148
- func safeSelectorExpr (
149
- expr * ast.SelectorExpr ,
150
- pass * analysis.Pass ,
151
- methodChecker func (node ast.Node , pass * analysis.Pass ) (bool , error ),
152
- ) (bool , error ) {
153
- ident , ok := expr .X .(* ast.Ident )
154
- if ! ok {
155
- return false , nil
156
- }
157
-
158
- methodName := expr .Sel .Name
159
- objType := pass .TypesInfo .ObjectOf (ident )
160
- pointerType , ok := objType .Type ().(* types.Pointer )
161
- if ! ok {
162
- return false , nil
163
- }
164
-
165
- named , ok := pointerType .Elem ().(* types.Named )
166
- if ! ok {
167
- return false , nil
168
- }
169
-
170
- result := false
171
- for i := 0 ; i < named .NumMethods (); i ++ {
172
- if named .Method (i ).Name () != methodName {
173
- continue
174
- }
175
-
176
- fset := pass .Fset
177
- position := fset .Position (named .Method (i ).Pos ())
178
- file , err := parser .ParseFile (fset , position .Filename , nil , 0 )
179
- if err != nil {
180
- return false , fmt .Errorf ("parse file: %w" , err )
181
- }
182
-
183
- for _ , decl := range file .Decls {
184
- if funcDecl , ok := decl .(* ast.FuncDecl ); ok {
185
- if funcDecl .Name .Name == methodName {
186
- result , err = methodChecker (funcDecl , pass )
187
- break
188
- }
189
- }
190
- }
191
- }
192
-
193
- return result , nil
114
+ return result
194
115
}
195
116
196
117
func isRecover (callExpr * ast.CallExpr ) bool {
@@ -199,7 +120,7 @@ func isRecover(callExpr *ast.CallExpr) bool {
199
120
return false
200
121
}
201
122
202
- return ident .Name == "recover"
123
+ return ident .Name == "recover" || ident . Name == customRecover
203
124
}
204
125
205
126
func isCustomRecover (callExpr * ast.CallExpr ) bool {
0 commit comments