mirror of
				https://github.com/mgechev/revive.git
				synced 2025-10-30 23:37:49 +02:00 
			
		
		
		
	fix #863:false positive on return statement in a func lit passed to the deferred function (#870)
This commit is contained in:
		| @@ -97,18 +97,21 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor { | ||||
| 			w.newFailure("return in a defer function has no effect", n, 1.0, "logic", "return") | ||||
| 		} | ||||
| 	case *ast.CallExpr: | ||||
| 		if !w.inADefer && isIdent(n.Fun, "recover") { | ||||
| 		isCallToRecover := isIdent(n.Fun, "recover") | ||||
| 		switch { | ||||
| 		case !w.inADefer && isCallToRecover: | ||||
| 			// func fn() { recover() } | ||||
| 			// | ||||
| 			// confidence is not 1 because recover can be in a function that is deferred elsewhere | ||||
| 			w.newFailure("recover must be called inside a deferred function", n, 0.8, "logic", "recover") | ||||
| 		} else if w.inADefer && !w.inAFuncLit && isIdent(n.Fun, "recover") { | ||||
| 		case w.inADefer && !w.inAFuncLit && isCallToRecover: | ||||
| 			// defer helper(recover()) | ||||
| 			// | ||||
| 			// confidence is not truly 1 because this could be in a correctly-deferred func, | ||||
| 			// but it is very likely to be a misunderstanding of defer's behavior around arguments. | ||||
| 			w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover") | ||||
| 		} | ||||
|  | ||||
| 	case *ast.DeferStmt: | ||||
| 		if isIdent(n.Call.Fun, "recover") { | ||||
| 			// defer recover() | ||||
| @@ -119,8 +122,13 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor { | ||||
| 		} | ||||
| 		w.visitSubtree(n.Call.Fun, true, false, false) | ||||
| 		for _, a := range n.Call.Args { | ||||
| 			switch a.(type) { | ||||
| 			case *ast.FuncLit: | ||||
| 				continue // too hard to analyze deferred calls with func literals args | ||||
| 			default: | ||||
| 				w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover() | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if w.inALoop { | ||||
| 			w.newFailure("prefer not to defer inside loops", n, 1.0, "bad practice", "loop") | ||||
| @@ -136,6 +144,7 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor { | ||||
| 					w.newFailure("be careful when deferring calls to methods without pointer receiver", fn, 0.8, "bad practice", "method-call") | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										14
									
								
								testdata/defer.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								testdata/defer.go
									
									
									
									
										vendored
									
									
								
							| @@ -33,3 +33,17 @@ func deferrer() { | ||||
| 	// does not work, but not currently blocked. | ||||
| 	defer helper(func() { recover() }) | ||||
| } | ||||
|  | ||||
| // Issue #863 | ||||
|  | ||||
| func verify(fn func() error) { | ||||
| 	if err := fn(); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func f() { | ||||
| 	defer verify(func() error { | ||||
| 		return nil | ||||
| 	}) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user