Skip to content

Commit 9acfcc8

Browse files
authored
fix #863:false positive on return statement in a func lit passed to the deferred function (#870)
1 parent 519ffbd commit 9acfcc8

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

rule/defer.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,21 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
9797
w.newFailure("return in a defer function has no effect", n, 1.0, "logic", "return")
9898
}
9999
case *ast.CallExpr:
100-
if !w.inADefer && isIdent(n.Fun, "recover") {
100+
isCallToRecover := isIdent(n.Fun, "recover")
101+
switch {
102+
case !w.inADefer && isCallToRecover:
101103
// func fn() { recover() }
102104
//
103105
// confidence is not 1 because recover can be in a function that is deferred elsewhere
104106
w.newFailure("recover must be called inside a deferred function", n, 0.8, "logic", "recover")
105-
} else if w.inADefer && !w.inAFuncLit && isIdent(n.Fun, "recover") {
107+
case w.inADefer && !w.inAFuncLit && isCallToRecover:
106108
// defer helper(recover())
107109
//
108110
// confidence is not truly 1 because this could be in a correctly-deferred func,
109111
// but it is very likely to be a misunderstanding of defer's behavior around arguments.
110112
w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover")
111113
}
114+
112115
case *ast.DeferStmt:
113116
if isIdent(n.Call.Fun, "recover") {
114117
// defer recover()
@@ -119,7 +122,12 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
119122
}
120123
w.visitSubtree(n.Call.Fun, true, false, false)
121124
for _, a := range n.Call.Args {
122-
w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover()
125+
switch a.(type) {
126+
case *ast.FuncLit:
127+
continue // too hard to analyze deferred calls with func literals args
128+
default:
129+
w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover()
130+
}
123131
}
124132

125133
if w.inALoop {
@@ -136,6 +144,7 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
136144
w.newFailure("be careful when deferring calls to methods without pointer receiver", fn, 0.8, "bad practice", "method-call")
137145
}
138146
}
147+
139148
}
140149
return nil
141150
}

testdata/defer.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,17 @@ func deferrer() {
3333
// does not work, but not currently blocked.
3434
defer helper(func() { recover() })
3535
}
36+
37+
// Issue #863
38+
39+
func verify(fn func() error) {
40+
if err := fn(); err != nil {
41+
panic(err)
42+
}
43+
}
44+
45+
func f() {
46+
defer verify(func() error {
47+
return nil
48+
})
49+
}

0 commit comments

Comments
 (0)