diff --git a/cmd/cover/cover.go b/cmd/cover/cover.go index ceaf3cfa..6826f0bb 100644 --- a/cmd/cover/cover.go +++ b/cmd/cover/cover.go @@ -550,6 +550,16 @@ func (f *File) endsBasicSourceBlock(s ast.Stmt) bool { return true case *ast.TypeSwitchStmt: return true + case *ast.ExprStmt: + // Calls to panic change the flow. + // We really should verify that "panic" is the predefined function, + // but without type checking we can't and the likelihood of it being + // an actual problem is vanishingly small. + if call, ok := s.X.(*ast.CallExpr); ok { + if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 { + return true + } + } } found, _ := hasFuncLiteral(s) return found diff --git a/cmd/cover/testdata/main.go b/cmd/cover/testdata/main.go index c704b157..6ed39c4f 100644 --- a/cmd/cover/testdata/main.go +++ b/cmd/cover/testdata/main.go @@ -58,12 +58,31 @@ func verify() { PASS = false } } + verifyPanic() if !PASS { fmt.Fprintf(os.Stderr, "FAIL\n") os.Exit(2) } } +// verifyPanic is a special check for the known counter that should be +// after the panic call in testPanic. +func verifyPanic() { + if coverTest.Count[panicIndex-1] != 1 { + // Sanity check for test before panic. + fmt.Fprintf(os.Stderr, "bad before panic") + PASS = false + } + if coverTest.Count[panicIndex] != 0 { + fmt.Fprintf(os.Stderr, "bad at panic: %d should be 0\n", coverTest.Count[panicIndex]) + PASS = false + } + if coverTest.Count[panicIndex+1] != 1 { + fmt.Fprintf(os.Stderr, "bad after panic") + PASS = false + } +} + // count returns the count and index for the counter at the specified line. func count(line uint32) (uint32, int) { // Linear search is fine. Choose perfect fit over approximate. diff --git a/cmd/cover/testdata/test.go b/cmd/cover/testdata/test.go index 8366f674..16c349c3 100644 --- a/cmd/cover/testdata/test.go +++ b/cmd/cover/testdata/test.go @@ -22,9 +22,26 @@ func testAll() { testTypeSwitch() testSelect1() testSelect2() + testPanic() testEmptySwitches() } +// The indexes of the counters in testPanic are known to main.go +const panicIndex = 3 + +// This test appears first because the index of its counters is known to main.go +func testPanic() { + defer func() { + recover() + }() + check(LINE, 1) + panic("should not get next line") + check(LINE, 0) // this is GoCover.Count[panicIndex] + // The next counter is in testSimple and it will be non-zero. + // If the panic above does not trigger a counter, the test will fail + // because GoCover.Count[panicIndex] will be the one in testSimple. +} + func testSimple() { check(LINE, 1) }