@@ -25,49 +25,6 @@ func init() {
25
25
var (
26
26
// ErrNoGoFiles is returned when CheckPackage is run on a package with no Go source files
27
27
ErrNoGoFiles = errors .New ("package contains no go source files" )
28
-
29
- // DefaultExcludedSymbols is a list of symbol names that are usually excluded from checks by default.
30
- //
31
- // Note, that they still need to be explicitly copied to Checker.Exclusions.Symbols
32
- DefaultExcludedSymbols = []string {
33
- // bytes
34
- "(*bytes.Buffer).Write" ,
35
- "(*bytes.Buffer).WriteByte" ,
36
- "(*bytes.Buffer).WriteRune" ,
37
- "(*bytes.Buffer).WriteString" ,
38
-
39
- // fmt
40
- "fmt.Errorf" ,
41
- "fmt.Print" ,
42
- "fmt.Printf" ,
43
- "fmt.Println" ,
44
- "fmt.Fprint(*bytes.Buffer)" ,
45
- "fmt.Fprintf(*bytes.Buffer)" ,
46
- "fmt.Fprintln(*bytes.Buffer)" ,
47
- "fmt.Fprint(*strings.Builder)" ,
48
- "fmt.Fprintf(*strings.Builder)" ,
49
- "fmt.Fprintln(*strings.Builder)" ,
50
- "fmt.Fprint(os.Stderr)" ,
51
- "fmt.Fprintf(os.Stderr)" ,
52
- "fmt.Fprintln(os.Stderr)" ,
53
-
54
- // io
55
- "(*io.PipeReader).CloseWithError" ,
56
- "(*io.PipeWriter).CloseWithError" ,
57
-
58
- // math/rand
59
- "math/rand.Read" ,
60
- "(*math/rand.Rand).Read" ,
61
-
62
- // strings
63
- "(*strings.Builder).Write" ,
64
- "(*strings.Builder).WriteByte" ,
65
- "(*strings.Builder).WriteRune" ,
66
- "(*strings.Builder).WriteString" ,
67
-
68
- // hash
69
- "(hash.Hash).Write" ,
70
- }
71
28
)
72
29
73
30
// UncheckedError indicates the position of an unchecked error return.
@@ -261,16 +218,17 @@ func (c *Checker) CheckPackage(pkg *packages.Package) Result {
261
218
}
262
219
263
220
v := & visitor {
264
- pkg : pkg ,
265
- ignore : ignore ,
266
- blank : ! c .Exclusions .BlankAssignments ,
267
- asserts : ! c .Exclusions .TypeAssertions ,
268
- lines : make (map [string ][]string ),
269
- exclude : excludedSymbols ,
270
- errors : []UncheckedError {},
221
+ typesInfo : pkg .TypesInfo ,
222
+ fset : pkg .Fset ,
223
+ ignore : ignore ,
224
+ blank : ! c .Exclusions .BlankAssignments ,
225
+ asserts : ! c .Exclusions .TypeAssertions ,
226
+ lines : make (map [string ][]string ),
227
+ exclude : excludedSymbols ,
228
+ errors : []UncheckedError {},
271
229
}
272
230
273
- for _ , astFile := range v . pkg .Syntax {
231
+ for _ , astFile := range pkg .Syntax {
274
232
if c .shouldSkipFile (astFile ) {
275
233
continue
276
234
}
@@ -281,12 +239,13 @@ func (c *Checker) CheckPackage(pkg *packages.Package) Result {
281
239
282
240
// visitor implements the errcheck algorithm
283
241
type visitor struct {
284
- pkg * packages.Package
285
- ignore map [string ]* regexp.Regexp
286
- blank bool
287
- asserts bool
288
- lines map [string ][]string
289
- exclude map [string ]bool
242
+ typesInfo * types.Info
243
+ fset * token.FileSet
244
+ ignore map [string ]* regexp.Regexp
245
+ blank bool
246
+ asserts bool
247
+ lines map [string ][]string
248
+ exclude map [string ]bool
290
249
291
250
errors []UncheckedError
292
251
}
@@ -306,7 +265,7 @@ func (v *visitor) selectorAndFunc(call *ast.CallExpr) (*ast.SelectorExpr, *types
306
265
return nil , nil , false
307
266
}
308
267
309
- fn , ok := v .pkg . TypesInfo .ObjectOf (sel .Sel ).(* types.Func )
268
+ fn , ok := v .typesInfo .ObjectOf (sel .Sel ).(* types.Func )
310
269
if ! ok {
311
270
// Shouldn't happen, but be paranoid
312
271
return nil , nil , false
@@ -393,7 +352,7 @@ func (v *visitor) namesForExcludeCheck(call *ast.CallExpr) []string {
393
352
394
353
// This will be missing for functions without a receiver (like fmt.Printf),
395
354
// so just fall back to the the function's fullName in that case.
396
- selection , ok := v .pkg . TypesInfo .Selections [sel ]
355
+ selection , ok := v .typesInfo .Selections [sel ]
397
356
if ! ok {
398
357
return []string {name }
399
358
}
@@ -420,14 +379,14 @@ func (v *visitor) namesForExcludeCheck(call *ast.CallExpr) []string {
420
379
func (v * visitor ) argName (expr ast.Expr ) string {
421
380
// Special-case literal "os.Stdout" and "os.Stderr"
422
381
if sel , ok := expr .(* ast.SelectorExpr ); ok {
423
- if obj := v .pkg . TypesInfo .ObjectOf (sel .Sel ); obj != nil {
382
+ if obj := v .typesInfo .ObjectOf (sel .Sel ); obj != nil {
424
383
vr , ok := obj .(* types.Var )
425
384
if ok && vr .Pkg () != nil && vr .Pkg ().Name () == "os" && (vr .Name () == "Stderr" || vr .Name () == "Stdout" ) {
426
385
return "os." + vr .Name ()
427
386
}
428
387
}
429
388
}
430
- t := v .pkg . TypesInfo .TypeOf (expr )
389
+ t := v .typesInfo .TypeOf (expr )
431
390
if t == nil {
432
391
return ""
433
392
}
@@ -478,7 +437,7 @@ func (v *visitor) ignoreCall(call *ast.CallExpr) bool {
478
437
return true
479
438
}
480
439
481
- if obj := v .pkg . TypesInfo .Uses [id ]; obj != nil {
440
+ if obj := v .typesInfo .Uses [id ]; obj != nil {
482
441
if pkg := obj .Pkg (); pkg != nil {
483
442
if re , ok := v .ignore [nonVendoredPkgPath (pkg .Path ())]; ok {
484
443
return re .MatchString (id .Name )
@@ -504,7 +463,7 @@ func nonVendoredPkgPath(pkgPath string) string {
504
463
// len(s) == number of return types of call
505
464
// s[i] == true iff return type at position i from left is an error type
506
465
func (v * visitor ) errorsByArg (call * ast.CallExpr ) []bool {
507
- switch t := v .pkg . TypesInfo .Types [call ].Type .(type ) {
466
+ switch t := v .typesInfo .Types [call ].Type .(type ) {
508
467
case * types.Named :
509
468
// Single return
510
469
return []bool {isErrorType (t )}
@@ -546,15 +505,18 @@ func (v *visitor) callReturnsError(call *ast.CallExpr) bool {
546
505
// isRecover returns true if the given CallExpr is a call to the built-in recover() function.
547
506
func (v * visitor ) isRecover (call * ast.CallExpr ) bool {
548
507
if fun , ok := call .Fun .(* ast.Ident ); ok {
549
- if _ , ok := v .pkg . TypesInfo .Uses [fun ].(* types.Builtin ); ok {
508
+ if _ , ok := v .typesInfo .Uses [fun ].(* types.Builtin ); ok {
550
509
return fun .Name == "recover"
551
510
}
552
511
}
553
512
return false
554
513
}
555
514
515
+ // TODO (dtcaciuc) collect token.Pos and then convert them to UncheckedErrors
516
+ // after visitor is done running. This will allow to integrate more cleanly
517
+ // with analyzer so that we don't have to convert Position back to Pos.
556
518
func (v * visitor ) addErrorAtPosition (position token.Pos , call * ast.CallExpr ) {
557
- pos := v .pkg . Fset .Position (position )
519
+ pos := v .fset .Position (position )
558
520
lines , ok := v .lines [pos .Filename ]
559
521
if ! ok {
560
522
lines = readfile (pos .Filename )
0 commit comments