зеркало из https://github.com/golang/tools.git
cmd/cover: cover funcs in if, for, switch clauses
This peculiar case arose in range statements but there are other contexts and one turned up in the auto-generated translation of the compiler. Take care of it always. for i := 0; i < 0; func() {i++; q=q.Link}() { ... } That code has been given the obvious rewrite but we should still handle it. Odd but easy to fix (tricky to test). Fixes #10269. Change-Id: I66e1404eb24da15a24be7f67403e19ed66fba0a7 Reviewed-on: https://go-review.googlesource.com/8284 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Родитель
dce4131cda
Коммит
65b5a8eca7
|
@ -503,6 +503,9 @@ func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClo
|
||||||
// Therefore we draw a line at the start of the body of the first function literal we find.
|
// Therefore we draw a line at the start of the body of the first function literal we find.
|
||||||
// TODO: what if there's more than one? Probably doesn't matter much.
|
// TODO: what if there's more than one? Probably doesn't matter much.
|
||||||
func hasFuncLiteral(n ast.Node) (bool, token.Pos) {
|
func hasFuncLiteral(n ast.Node) (bool, token.Pos) {
|
||||||
|
if n == nil {
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
var literal funcLitFinder
|
var literal funcLitFinder
|
||||||
ast.Walk(&literal, n)
|
ast.Walk(&literal, n)
|
||||||
return literal.found(), token.Pos(literal)
|
return literal.found(), token.Pos(literal)
|
||||||
|
@ -517,24 +520,54 @@ func (f *File) statementBoundary(s ast.Stmt) token.Pos {
|
||||||
// Treat blocks like basic blocks to avoid overlapping counters.
|
// Treat blocks like basic blocks to avoid overlapping counters.
|
||||||
return s.Lbrace
|
return s.Lbrace
|
||||||
case *ast.IfStmt:
|
case *ast.IfStmt:
|
||||||
|
found, pos := hasFuncLiteral(s.Init)
|
||||||
|
if found {
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
found, pos = hasFuncLiteral(s.Cond)
|
||||||
|
if found {
|
||||||
|
return pos
|
||||||
|
}
|
||||||
return s.Body.Lbrace
|
return s.Body.Lbrace
|
||||||
case *ast.ForStmt:
|
case *ast.ForStmt:
|
||||||
|
found, pos := hasFuncLiteral(s.Init)
|
||||||
|
if found {
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
found, pos = hasFuncLiteral(s.Cond)
|
||||||
|
if found {
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
found, pos = hasFuncLiteral(s.Post)
|
||||||
|
if found {
|
||||||
|
return pos
|
||||||
|
}
|
||||||
return s.Body.Lbrace
|
return s.Body.Lbrace
|
||||||
case *ast.LabeledStmt:
|
case *ast.LabeledStmt:
|
||||||
return f.statementBoundary(s.Stmt)
|
return f.statementBoundary(s.Stmt)
|
||||||
case *ast.RangeStmt:
|
case *ast.RangeStmt:
|
||||||
// Ranges might loop over things with function literals.: for _ = range []func(){ ... } {.
|
|
||||||
// TODO: There are a few other such possibilities, but they're extremely unlikely.
|
|
||||||
found, pos := hasFuncLiteral(s.X)
|
found, pos := hasFuncLiteral(s.X)
|
||||||
if found {
|
if found {
|
||||||
return pos
|
return pos
|
||||||
}
|
}
|
||||||
return s.Body.Lbrace
|
return s.Body.Lbrace
|
||||||
case *ast.SwitchStmt:
|
case *ast.SwitchStmt:
|
||||||
|
found, pos := hasFuncLiteral(s.Init)
|
||||||
|
if found {
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
found, pos = hasFuncLiteral(s.Tag)
|
||||||
|
if found {
|
||||||
|
return pos
|
||||||
|
}
|
||||||
return s.Body.Lbrace
|
return s.Body.Lbrace
|
||||||
case *ast.SelectStmt:
|
case *ast.SelectStmt:
|
||||||
return s.Body.Lbrace
|
return s.Body.Lbrace
|
||||||
case *ast.TypeSwitchStmt:
|
case *ast.TypeSwitchStmt:
|
||||||
|
found, pos := hasFuncLiteral(s.Init)
|
||||||
|
if found {
|
||||||
|
return pos
|
||||||
|
}
|
||||||
return s.Body.Lbrace
|
return s.Body.Lbrace
|
||||||
}
|
}
|
||||||
// If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal.
|
// If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal.
|
||||||
|
|
|
@ -86,10 +86,13 @@ func testIf() {
|
||||||
check(LINE, 0)
|
check(LINE, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if func(a, b int) bool { return a < b }(3, 4) {
|
||||||
|
check(LINE, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFor() {
|
func testFor() {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; func() { i++; check(LINE, 10) }() {
|
||||||
check(LINE, 10)
|
check(LINE, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +125,7 @@ func testBlockRun() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSwitch() {
|
func testSwitch() {
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; func() { i++; check(LINE, 5) }() {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
check(LINE, 1)
|
check(LINE, 1)
|
||||||
|
@ -139,7 +142,7 @@ func testSwitch() {
|
||||||
func testTypeSwitch() {
|
func testTypeSwitch() {
|
||||||
var x = []interface{}{1, 2.0, "hi"}
|
var x = []interface{}{1, 2.0, "hi"}
|
||||||
for _, v := range x {
|
for _, v := range x {
|
||||||
switch v.(type) {
|
switch func() { check(LINE, 3) }(); v.(type) {
|
||||||
case int:
|
case int:
|
||||||
check(LINE, 1)
|
check(LINE, 1)
|
||||||
case float64:
|
case float64:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче