Skip to content

Commit 9b8014a

Browse files
committed
Add analyzer tests
1 parent 7154fcc commit 9b8014a

File tree

8 files changed

+210
-1
lines changed

8 files changed

+210
-1
lines changed

errcheck/analyzer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,14 @@ func runAnalyzer(pass *analysis.Pass) (interface{}, error) {
6464

6565
ast.Walk(v, f)
6666

67+
// TODO have visitor report all facts and then sort out
68+
// the ones we need to report based on flags. This can
69+
// likely simplify the visitor code.
70+
6771
for _, err := range v.errors {
6872
pass.Report(analysis.Diagnostic{
6973
Pos: token.Pos(int(f.Pos()) + err.Pos.Offset),
70-
Message: fmt.Sprintf("unchecked error returned by %s", err.FuncName),
74+
Message: "unchecked error",
7175
})
7276
}
7377

errcheck/errcheck.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ func (v *visitor) isRecover(call *ast.CallExpr) bool {
512512
return false
513513
}
514514

515+
// TODO 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.
515518
func (v *visitor) addErrorAtPosition(position token.Pos, call *ast.CallExpr) {
516519
pos := v.fset.Position(position)
517520
lines, ok := v.lines[pos.Filename]

errcheck/testdata/custom_exclude.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(custom_exclude.ErrorMakerInterfaceWrapper).MakeNilError

errcheck/testdata/src/a/main.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package a
2+
3+
import (
4+
"bytes"
5+
"crypto/sha256"
6+
"fmt"
7+
"io/ioutil"
8+
"math/rand"
9+
mrand "math/rand"
10+
)
11+
12+
func a() error {
13+
fmt.Println("this function returns an error") // ok, excluded
14+
return nil
15+
}
16+
17+
func b() (int, error) {
18+
fmt.Println("this function returns an int and an error") // ok, excluded
19+
return 0, nil
20+
}
21+
22+
func c() int {
23+
fmt.Println("this function returns an int") // ok, excluded
24+
return 7
25+
}
26+
27+
func rec() {
28+
defer func() {
29+
recover() // want "unchecked error"
30+
_ = recover() // ok, assigned to blank
31+
}()
32+
defer recover() // want "unchecked error"
33+
}
34+
35+
type MyError string
36+
37+
func (e MyError) Error() string {
38+
return string(e)
39+
}
40+
41+
func customError() error {
42+
return MyError("an error occurred")
43+
}
44+
45+
func customConcreteError() MyError {
46+
return MyError("an error occurred")
47+
}
48+
49+
func customConcreteErrorTuple() (int, MyError) {
50+
return 0, MyError("an error occurred")
51+
}
52+
53+
type MyPointerError string
54+
55+
func (e *MyPointerError) Error() string {
56+
return string(*e)
57+
}
58+
59+
func customPointerError() *MyPointerError {
60+
e := MyPointerError("an error occurred")
61+
return &e
62+
}
63+
64+
func customPointerErrorTuple() (int, *MyPointerError) {
65+
e := MyPointerError("an error occurred")
66+
return 0, &e
67+
}
68+
69+
type ErrorMakerInterface interface {
70+
MakeNilError() error
71+
}
72+
type ErrorMakerInterfaceWrapper interface {
73+
ErrorMakerInterface
74+
}
75+
76+
func main() {
77+
// Single error return
78+
_ = a() // ok, assigned to blank
79+
a() // want "unchecked error"
80+
81+
// Return another value and an error
82+
_, _ = b() // ok, assigned to blank
83+
b() // want "unchecked error"
84+
85+
// Return a custom error type
86+
_ = customError() // ok, assigned to blank
87+
customError() // want "unchecked error"
88+
89+
// Return a custom concrete error type
90+
_ = customConcreteError() // ok, assigned to blank
91+
customConcreteError() // want "unchecked error"
92+
_, _ = customConcreteErrorTuple() // ok, assigned to blank
93+
customConcreteErrorTuple() // want "unchecked error"
94+
95+
// Return a custom pointer error type
96+
_ = customPointerError() // ok, assigned to blank
97+
customPointerError() // want "unchecked error"
98+
_, _ = customPointerErrorTuple() // ok, assigned to blank
99+
customPointerErrorTuple() // want "unchecked error"
100+
101+
// Method with a single error return
102+
x := t{}
103+
_ = x.a() // ok, assigned to blank
104+
x.a() // want "unchecked error"
105+
106+
// Method call on a struct member
107+
y := u{x}
108+
_ = y.t.a() // ok, assigned to blank
109+
y.t.a() // want "unchecked error"
110+
111+
m1 := map[string]func() error{"a": a}
112+
_ = m1["a"]() // ok, assigned to blank
113+
m1["a"]() // want "unchecked error"
114+
115+
// Additional cases for assigning errors to blank identifier
116+
z, _ := b() // ok, assigned to blank
117+
_, w := a(), 5 // ok, assigned to blank
118+
119+
// Assign non error to blank identifier
120+
_ = c()
121+
122+
_ = z + w // Avoid complaints about unused variables
123+
124+
// Type assertions
125+
var i interface{}
126+
s1 := i.(string) // ok, would fail with -assert
127+
s1 = i.(string) // ok, would fail with -assert
128+
s2, _ := i.(string) // ok, would fail with -blank
129+
s2, _ = i.(string) // ok, would fail with -blank
130+
s3, ok := i.(string)
131+
s3, ok = i.(string)
132+
switch s4 := i.(type) {
133+
case string:
134+
_ = s4
135+
}
136+
_, _, _, _ = s1, s2, s3, ok
137+
138+
// Goroutine
139+
go a() // want "unchecked error"
140+
defer a() // want "unchecked error"
141+
142+
// IO errors excluded by default
143+
b1 := bytes.Buffer{}
144+
b2 := &bytes.Buffer{}
145+
b1.Write(nil)
146+
b2.Write(nil)
147+
rand.Read(nil)
148+
mrand.Read(nil)
149+
sha256.New().Write([]byte{})
150+
151+
ioutil.ReadFile("main.go") // want "unchecked error"
152+
153+
var emiw ErrorMakerInterfaceWrapper
154+
emiw.MakeNilError() // want "unchecked error"
155+
}

errcheck/testdata/src/a/t.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// This file exists so that we can check that multi-file packages work
2+
package a
3+
4+
import "fmt"
5+
6+
type t struct{}
7+
8+
func (x t) a() error {
9+
fmt.Println("this method returns an error") // EXCLUDED
10+
//line myfile.txt:100
11+
fmt.Println("this method also returns an error") // EXCLUDED
12+
return nil
13+
}
14+
15+
type u struct {
16+
t t
17+
}

errcheck/testdata/src/assert/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package assert
2+
3+
func main() {
4+
var i interface{}
5+
_ = i.(string) // want "unchecked error"
6+
}

errcheck/testdata/src/blank/main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package blank
2+
3+
func a() error {
4+
return nil
5+
}
6+
7+
func main() {
8+
_ = a() // want "unchecked error"
9+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package custom_excludes
2+
3+
// Test custom excludes
4+
type ErrorMakerInterface interface {
5+
MakeNilError() error
6+
}
7+
type ErrorMakerInterfaceWrapper interface {
8+
ErrorMakerInterface
9+
}
10+
11+
func main() {
12+
var emiw ErrorMakerInterfaceWrapper
13+
emiw.MakeNilError() // ok, custom exclude
14+
}

0 commit comments

Comments
 (0)