From b03e54f617491984b41f0411b69326f94d03a76f Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Thu, 16 Mar 2023 13:39:52 -0700 Subject: [PATCH] empty-block: Fix false positive on select {} (#805) This fixes a false positive reported by revive on the following: select {} This is a way to block the program indefinitely. It is used in cases like: - Running a long-running server in a background thread and blocking `main` from exiting until the application dies. This is something you might do if your process has multiple servers/listeners in the same process. ```go go grpcListenAndServe() go httpListenAndServe() go logFlusher() select {} ``` - In programs compiled to WASM to prevent the application from exiting, so that the Javascript components may interact with it. ```go func main() { js.Global().Set("foo", foo) select {} } ``` Without this, one may see an error like, "Error: Go program has already exited" As a workaround, these programs can block forever by receiving from a throwaway channel (`<-make(chan struct{})`), but `select {}` is still a completely valid way of doing this, so supporting it makes sense. The issue was previously reported in #698 but was closed because the author was satisfied with a `//nolint` comment. Now that this rule is part of the default rule set (#799) the case for addressing the false positive is stronger. Resolves #804 --- rule/empty-block.go | 3 +++ testdata/empty-block.go | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/rule/empty-block.go b/rule/empty-block.go index 8a4a0fef1..17652555f 100644 --- a/rule/empty-block.go +++ b/rule/empty-block.go @@ -40,6 +40,9 @@ func (w lintEmptyBlock) Visit(node ast.Node) ast.Visitor { case *ast.FuncLit: w.ignore[n.Body] = true return w + case *ast.SelectStmt: + w.ignore[n.Body] = true + return w case *ast.RangeStmt: if len(n.Body.List) == 0 { w.onFailure(lint.Failure{ diff --git a/testdata/empty-block.go b/testdata/empty-block.go index d75015757..ee257d001 100644 --- a/testdata/empty-block.go +++ b/testdata/empty-block.go @@ -2,6 +2,8 @@ package fixtures +import "net/http" + func f(x int) {} // Must not match type foo struct{} @@ -9,6 +11,12 @@ type foo struct{} func (f foo) f(x *int) {} // Must not match func (f *foo) g(y *int) {} // Must not match + +func h() { + go http.ListenAndServe() + select {} // Must not match +} + func g(f func() bool) { { // MATCH /this block is empty, you can remove it/ } @@ -44,4 +52,9 @@ func g(f func() bool) { for range s { // MATCH /this block is empty, you can remove it/ } + select { + case _, ok := <-c: + if ok { // MATCH /this block is empty, you can remove it/ + } + } }