diff --git a/go/analysis/passes/lostcancel/lostcancel.go b/go/analysis/passes/lostcancel/lostcancel.go index fcf9f553..996ecc4d 100644 --- a/go/analysis/passes/lostcancel/lostcancel.go +++ b/go/analysis/passes/lostcancel/lostcancel.go @@ -132,11 +132,17 @@ func runFunc(pass *analysis.Pass, node ast.Node) { var sig *types.Signature switch node := node.(type) { case *ast.FuncDecl: - g = cfgs.FuncDecl(node) sig, _ = pass.TypesInfo.Defs[node.Name].Type().(*types.Signature) + if node.Name.Name == "main" && sig.Recv() == nil && pass.Pkg.Name() == "main" { + // Returning from main.main terminates the process, + // so there's no need to cancel contexts. + return + } + g = cfgs.FuncDecl(node) + case *ast.FuncLit: - g = cfgs.FuncLit(node) sig, _ = pass.TypesInfo.Types[node.Type].Type.(*types.Signature) + g = cfgs.FuncLit(node) } if sig == nil { return // missing type information diff --git a/go/analysis/passes/lostcancel/lostcancel_test.go b/go/analysis/passes/lostcancel/lostcancel_test.go index 5fe817b3..a1d8f854 100644 --- a/go/analysis/passes/lostcancel/lostcancel_test.go +++ b/go/analysis/passes/lostcancel/lostcancel_test.go @@ -13,5 +13,5 @@ import ( func Test(t *testing.T) { testdata := analysistest.TestData() - analysistest.Run(t, testdata, lostcancel.Analyzer, "a") + analysistest.Run(t, testdata, lostcancel.Analyzer, "a", "b") } diff --git a/go/analysis/passes/lostcancel/testdata/src/b/b.go b/go/analysis/passes/lostcancel/testdata/src/b/b.go new file mode 100644 index 00000000..18ef0348 --- /dev/null +++ b/go/analysis/passes/lostcancel/testdata/src/b/b.go @@ -0,0 +1,26 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "context" + +// Return from main is handled specially. +// Since the program exits, there's no need to call cancel. +func main() { + _, cancel := context.WithCancel(nil) + if maybe { + cancel() + } +} + +func notMain() { + _, cancel := context.WithCancel(nil) // want "cancel function.*not used" + + if maybe { + cancel() + } +} // want "return statement.*reached without using the cancel" + +var maybe bool