diff --git a/instrumenter.go b/instrumenter.go index 3a9e610..5a85715 100644 --- a/instrumenter.go +++ b/instrumenter.go @@ -25,10 +25,11 @@ type cond struct { // exprSubst prepares to later replace '*ref' with 'expr'. type exprSubst struct { - ref *ast.Expr - expr ast.Expr - pos token.Pos - text string + ref *ast.Expr + expr ast.Expr + pos token.Pos + text string + convert bool } // instrumenter rewrites the code of a go package @@ -248,7 +249,7 @@ func (i *instrumenter) findRefsField(field reflect.Value) { delete(i.marked, expr) ref := field.Addr().Interface().(*ast.Expr) i.exprSubst[expr] = &exprSubst{ - ref, expr, expr.Pos(), i.str(expr), + ref, expr, expr.Pos(), i.str(expr), true, } } @@ -257,7 +258,7 @@ func (i *instrumenter) findRefsField(field reflect.Value) { if i.marked[expr] { delete(i.marked, expr) i.exprSubst[expr] = &exprSubst{ - &val[ei], expr, expr.Pos(), i.str(expr), + &val[ei], expr, expr.Pos(), i.str(expr), true, } } } @@ -292,6 +293,13 @@ func (i *instrumenter) prepareStmts(n ast.Node) bool { func (i *instrumenter) prepareSwitchStmt(n *ast.SwitchStmt) { if n.Tag == nil { + for _, clause := range n.Body.List { + for _, expr := range clause.(*ast.CaseClause).List { + if s := i.exprSubst[expr]; s != nil { + s.convert = false + } + } + } return // Already handled in instrumenter.markConds. } @@ -318,6 +326,7 @@ func (i *instrumenter) prepareSwitchStmt(n *ast.SwitchStmt) { gen.eql(tagExprName, expr), expr.Pos(), i.strEql(n.Tag, expr), + false, } tagExprUsed = true } @@ -421,7 +430,7 @@ func (i *instrumenter) prepareTypeSwitchStmt(ts *ast.TypeSwitchStmt) { gen := codeGenerator{test.pos} ident := gen.ident(test.varname) - wrapped := i.callCover(ident, test.pos, test.code) + wrapped := i.callCover(ident, test.pos, test.code, false) newList = append(newList, wrapped) } @@ -458,7 +467,7 @@ func (i *instrumenter) replace(n ast.Node) bool { case ast.Expr: if s := i.exprSubst[n]; s != nil { - *s.ref = i.callCover(s.expr, s.pos, s.text) + *s.ref = i.callCover(s.expr, s.pos, s.text, s.convert) } case ast.Stmt: @@ -478,7 +487,7 @@ func (i *instrumenter) replace(n ast.Node) bool { // that is most closely related to the instrumented condition. // Especially for switch statements, // the position may differ from the expression that is wrapped. -func (i *instrumenter) callCover(expr ast.Expr, pos token.Pos, code string) ast.Expr { +func (i *instrumenter) callCover(expr ast.Expr, pos token.Pos, code string, convert bool) ast.Expr { assert(pos.IsValid(), "pos must refer to the code from before instrumentation") start := i.fset.Position(pos) @@ -491,7 +500,7 @@ func (i *instrumenter) callCover(expr ast.Expr, pos token.Pos, code string) ast. idx := len(i.conds) - 1 gen := codeGenerator{pos} - return gen.callGobcoCover(idx, expr) + return gen.callGobcoCover(idx, expr, convert) } // strEql returns the string representation of (lhs == rhs). @@ -712,8 +721,8 @@ func (gen codeGenerator) callFinish(arg ast.Expr) ast.Expr { } } -func (gen codeGenerator) callGobcoCover(idx int, cond ast.Expr) ast.Expr { - return &ast.CallExpr{ +func (gen codeGenerator) callGobcoCover(idx int, cond ast.Expr, convert bool) ast.Expr { + call := &ast.CallExpr{ Fun: gen.ident("GobcoCover"), Lparen: gen.pos, Args: []ast.Expr{ @@ -722,10 +731,32 @@ func (gen codeGenerator) callGobcoCover(idx int, cond ast.Expr) ast.Expr { Kind: token.INT, Value: fmt.Sprint(idx), }, - cond, + gen.toBool(cond), }, Rparen: gen.pos, } + if !convert { + return call + } + return gen.toCustomBool(call) +} + +func (gen codeGenerator) toBool(cond ast.Expr) ast.Expr { + switch cond.(type) { + case *ast.UnaryExpr, *ast.BinaryExpr: + return cond + default: + return gen.toCustomBool(cond) + } +} + +func (gen codeGenerator) toCustomBool(cond ast.Expr) ast.Expr { + return &ast.BinaryExpr{ + X: cond, + OpPos: gen.pos, + Op: token.EQL, + Y: gen.ident("true"), + } } func (gen codeGenerator) define(lhs string, rhs ast.Expr) *ast.AssignStmt { diff --git a/testdata/instrumenter/AssignStmt.cond b/testdata/instrumenter/AssignStmt.cond index 868f1e9..87ad1ff 100644 --- a/testdata/instrumenter/AssignStmt.cond +++ b/testdata/instrumenter/AssignStmt.cond @@ -17,20 +17,20 @@ func assignStmt() { assertEquals(i, 3) // Most assignments assign to a single variable. - mm[GobcoCover(0, i > 0)] = GobcoCover(1, i > 3) + mm[GobcoCover(0, i > 0) == true] = GobcoCover(1, i > 3) == true // An assignment can assign multiple variables simultaneously. - b1, m[GobcoCover(2, i > 0)], b2 = b2, m[GobcoCover(3, i > 1)], b1 - mm[GobcoCover(4, i > 10)], mm[GobcoCover(5, i > 11)], mm[GobcoCover(6, i > 12)] = - GobcoCover(7, i > 13), GobcoCover(8, i > 14), GobcoCover(9, i > 15) + b1, m[GobcoCover(2, i > 0) == true], b2 = b2, m[GobcoCover(3, i > 1) == true], b1 + mm[GobcoCover(4, i > 10) == true], mm[GobcoCover(5, i > 11) == true], mm[GobcoCover(6, i > 12) == true] = + GobcoCover(7, i > 13) == true, GobcoCover(8, i > 14) == true, GobcoCover(9, i > 15) == true // Assignments from a function call can assign to multiple variables. - mm[GobcoCover(10, i > 0)], mm[GobcoCover(11, i > 1)], mm[GobcoCover(12, i > 2)] = + mm[GobcoCover(10, i > 0) == true], mm[GobcoCover(11, i > 1) == true], mm[GobcoCover(12, i > 2) == true] = func() (bool, bool, bool) { return false, false, false }() // Operands may be parenthesized. - (m[GobcoCover(13, i > 21)]), (m[GobcoCover(14, i > 22)]) = - (m[GobcoCover(15, i > 23)]), (m[GobcoCover(16, i > 24)]) + (m[GobcoCover(13, i > 21) == true]), (m[GobcoCover(14, i > 22) == true]) = + (m[GobcoCover(15, i > 23) == true]), (m[GobcoCover(16, i > 24) == true]) // Since the left-hand side in an assignment must be a variable, // and since only those expressions are instrumented that are diff --git a/testdata/instrumenter/BinaryExpr.branch b/testdata/instrumenter/BinaryExpr.branch index 5ba34d6..1c59413 100644 --- a/testdata/instrumenter/BinaryExpr.branch +++ b/testdata/instrumenter/BinaryExpr.branch @@ -71,10 +71,10 @@ func binaryExpr(i int, a bool, b bool, c bool) { // if statements; in branch coverage mode, only instrument the main // condition. mi := map[bool]int{} - if GobcoCover(0, i == mi[i > 51]) { + if GobcoCover(0, i == mi[i > 51]) == true { _ = i == mi[i > 52] } - for GobcoCover(1, i == mi[i > 61]) { + for GobcoCover(1, i == mi[i > 61]) == true { _ = i == mi[i > 62] } } diff --git a/testdata/instrumenter/BinaryExpr.cond b/testdata/instrumenter/BinaryExpr.cond index 17be0a7..9ee7157 100644 --- a/testdata/instrumenter/BinaryExpr.cond +++ b/testdata/instrumenter/BinaryExpr.cond @@ -17,8 +17,8 @@ package instrumenter func binaryExpr(i int, a bool, b bool, c bool) { // Comparison expressions have return type boolean and are // therefore instrumented. - _ = GobcoCover(0, i > 0) - pos := GobcoCover(1, i > 0) + _ = GobcoCover(0, i > 0) == true + pos := GobcoCover(1, i > 0) == true // Expressions consisting of a single identifier do not look like boolean // expressions, therefore they are not instrumented. @@ -32,50 +32,50 @@ func binaryExpr(i int, a bool, b bool, c bool) { // // Also, gobco only looks at the parse tree without any type resolution. // Therefore it cannot decide whether a variable is boolean or not. - both := GobcoCover(2, a) && GobcoCover(3, b) - either := GobcoCover(4, a) || GobcoCover(5, b) + both := GobcoCover(2, a == true) == true && GobcoCover(3, b == true) == true + either := GobcoCover(4, a == true) == true || GobcoCover(5, b == true) == true _, _ = both, either // When a long chain of '&&' or '||' is parsed, it is split into // the rightmost operand and the rest, instrumenting both these // parts. - _ = GobcoCover(6, i == 11) || - GobcoCover(7, i == 12) || - GobcoCover(8, i == 13) || - GobcoCover(9, i == 14) || - GobcoCover(10, i == 15) - _ = GobcoCover(11, i != 21) && - GobcoCover(12, i != 22) && - GobcoCover(13, i != 23) && - GobcoCover(14, i != 24) && - GobcoCover(15, i != 25) + _ = GobcoCover(6, i == 11) == true || + GobcoCover(7, i == 12) == true || + GobcoCover(8, i == 13) == true || + GobcoCover(9, i == 14) == true || + GobcoCover(10, i == 15) == true + _ = GobcoCover(11, i != 21) == true && + GobcoCover(12, i != 22) == true && + GobcoCover(13, i != 23) == true && + GobcoCover(14, i != 24) == true && + GobcoCover(15, i != 25) == true // The operators '&&' and '||' can be mixed as well. - _ = GobcoCover(16, i == 31) || - GobcoCover(17, i >= 32) && GobcoCover(18, i <= 33) || - GobcoCover(19, i >= 34) && GobcoCover(20, i <= 35) + _ = GobcoCover(16, i == 31) == true || + GobcoCover(17, i >= 32) == true && GobcoCover(18, i <= 33) == true || + GobcoCover(19, i >= 34) == true && GobcoCover(20, i <= 35) == true m := map[bool]int{} - _ = GobcoCover(21, m[GobcoCover(22, i == 41)] == m[GobcoCover(23, i == 42)]) + _ = GobcoCover(21, m[GobcoCover(22, i == 41) == true] == m[GobcoCover(23, i == 42) == true]) == true // In condition coverage mode, do not instrument complex conditions // but instead their terminal conditions, in this case 'a', 'b' and // 'c', to avoid large and redundant conditions in the output. f := func(args ...bool) {} - f(GobcoCover(24, a) && GobcoCover(25, b)) - f(GobcoCover(26, a) && GobcoCover(27, b) && GobcoCover(28, c)) - f(!GobcoCover(29, a)) - f(!GobcoCover(30, a) && !GobcoCover(31, b) && !GobcoCover(32, c)) + f(GobcoCover(24, a == true) == true && GobcoCover(25, b == true) == true) + f(GobcoCover(26, a == true) == true && GobcoCover(27, b == true) == true && GobcoCover(28, c == true) == true) + f(!(GobcoCover(29, a == true) == true)) + f(!(GobcoCover(30, a == true) == true) && !(GobcoCover(31, b == true) == true) && !(GobcoCover(32, c == true) == true)) // In condition coverage mode, instrument deeply nested conditions in // if statements; in branch coverage mode, only instrument the main // condition. mi := map[bool]int{} - if GobcoCover(33, i == mi[GobcoCover(34, i > 51)]) { - _ = GobcoCover(35, i == mi[GobcoCover(36, i > 52)]) + if GobcoCover(33, i == mi[GobcoCover(34, i > 51) == true]) == true { + _ = GobcoCover(35, i == mi[GobcoCover(36, i > 52) == true]) == true } - for GobcoCover(37, i == mi[GobcoCover(38, i > 61)]) { - _ = GobcoCover(39, i == mi[GobcoCover(40, i > 62)]) + for GobcoCover(37, i == mi[GobcoCover(38, i > 61) == true]) == true { + _ = GobcoCover(39, i == mi[GobcoCover(40, i > 62) == true]) == true } } diff --git a/testdata/instrumenter/CallExpr.branch b/testdata/instrumenter/CallExpr.branch index 847b9a2..6db75ec 100644 --- a/testdata/instrumenter/CallExpr.branch +++ b/testdata/instrumenter/CallExpr.branch @@ -14,7 +14,7 @@ func callExpr(a bool, b string) bool { // not wrapped since, as of January 2023, gobco does not use type // resolution. - if GobcoCover(0, len(b) > 0) { + if GobcoCover(0, len(b) > 0) == true { return callExpr(len(b)%2 == 0, b[1:]) } @@ -29,7 +29,20 @@ func callExpr(a bool, b string) bool { type myBool bool _ = myBool(3 > 0) + // There may be custom types based on bool, + // and these types cannot be directly assigned to bool. + // https://github.com/rillig/gobco/issues/35 + toMyBool := func(i int) myBool { return i%2 == 0 } + if GobcoCover(1, toMyBool(4) == true) == true { + } + + fromMyBool := func(m myBool) bool { return bool(m) } + if GobcoCover(2, fromMyBool(toMyBool(3) && toMyBool(6)) == true) == true { + } + return false } // :17:5: "len(b) > 0" +// :36:5: "toMyBool(4)" +// :40:5: "fromMyBool(toMyBool(3) && toMyBool(6))" diff --git a/testdata/instrumenter/CallExpr.cond b/testdata/instrumenter/CallExpr.cond index 7cbea4b..349841d 100644 --- a/testdata/instrumenter/CallExpr.cond +++ b/testdata/instrumenter/CallExpr.cond @@ -14,20 +14,31 @@ func callExpr(a bool, b string) bool { // not wrapped since, as of January 2023, gobco does not use type // resolution. - if GobcoCover(0, len(b) > 0) { - return callExpr(GobcoCover(1, len(b)%2 == 0), b[1:]) + if GobcoCover(0, len(b) > 0) == true { + return callExpr(GobcoCover(1, len(b)%2 == 0) == true, b[1:]) } // A CallExpr without identifier is also covered. - (func(a bool) {})(GobcoCover(2, 1 != 2)) + (func(a bool) {})(GobcoCover(2, 1 != 2) == true) // The function expression can contain conditions as well. m := map[bool]func(){} - m[GobcoCover(3, 3 != 0)]() + m[GobcoCover(3, 3 != 0) == true]() // Type conversions end up as CallExpr as well. type myBool bool - _ = myBool(GobcoCover(4, 3 > 0)) + _ = myBool(GobcoCover(4, 3 > 0) == true) + + // There may be custom types based on bool, + // and these types cannot be directly assigned to bool. + // https://github.com/rillig/gobco/issues/35 + toMyBool := func(i int) myBool { return GobcoCover(5, i%2 == 0) == true } + if GobcoCover(6, toMyBool(4) == true) == true { + } + + fromMyBool := func(m myBool) bool { return bool(m) } + if GobcoCover(7, fromMyBool(GobcoCover(8, toMyBool(3) == true) == true && GobcoCover(9, toMyBool(6) == true) == true) == true) == true { + } return false } @@ -37,3 +48,8 @@ func callExpr(a bool, b string) bool { // :22:20: "1 != 2" // :26:4: "3 != 0" // :30:13: "3 > 0" +// :35:42: "i%2 == 0" +// :36:5: "toMyBool(4)" +// :40:5: "fromMyBool(toMyBool(3) && toMyBool(6))" +// :40:16: "toMyBool(3)" +// :40:31: "toMyBool(6)" diff --git a/testdata/instrumenter/CallExpr.go b/testdata/instrumenter/CallExpr.go index ed031c9..a017f5e 100644 --- a/testdata/instrumenter/CallExpr.go +++ b/testdata/instrumenter/CallExpr.go @@ -29,5 +29,16 @@ func callExpr(a bool, b string) bool { type myBool bool _ = myBool(3 > 0) + // There may be custom types based on bool, + // and these types cannot be directly assigned to bool. + // https://github.com/rillig/gobco/issues/35 + toMyBool := func(i int) myBool { return i%2 == 0 } + if toMyBool(4) { + } + + fromMyBool := func(m myBool) bool { return bool(m) } + if fromMyBool(toMyBool(3) && toMyBool(6)) { + } + return false } diff --git a/testdata/instrumenter/Comment.branch b/testdata/instrumenter/Comment.branch index a07ed28..7bb5ab0 100644 --- a/testdata/instrumenter/Comment.branch +++ b/testdata/instrumenter/Comment.branch @@ -33,23 +33,23 @@ func comment() { _, gobco4 := gobco0.([][]int) _, gobco5 := gobco0.([]int) switch { - case GobcoCover(0, gobco1): + case GobcoCover(0, gobco1 == true): // begin int _ = 1 // end int - case GobcoCover(1, gobco2): + case GobcoCover(1, gobco2 == true): // begin int-4D _ = 1 // end int-4D - case GobcoCover(2, gobco3): + case GobcoCover(2, gobco3 == true): // begin int-3D _ = 1 // end int-3D - case GobcoCover(3, gobco4): + case GobcoCover(3, gobco4 == true): // begin int-2D _ = 1 // end int-2D - case GobcoCover(4, gobco5): + case GobcoCover(4, gobco5 == true): // begin int-1D _ = 1 } diff --git a/testdata/instrumenter/Comment.cond b/testdata/instrumenter/Comment.cond index a07ed28..7bb5ab0 100644 --- a/testdata/instrumenter/Comment.cond +++ b/testdata/instrumenter/Comment.cond @@ -33,23 +33,23 @@ func comment() { _, gobco4 := gobco0.([][]int) _, gobco5 := gobco0.([]int) switch { - case GobcoCover(0, gobco1): + case GobcoCover(0, gobco1 == true): // begin int _ = 1 // end int - case GobcoCover(1, gobco2): + case GobcoCover(1, gobco2 == true): // begin int-4D _ = 1 // end int-4D - case GobcoCover(2, gobco3): + case GobcoCover(2, gobco3 == true): // begin int-3D _ = 1 // end int-3D - case GobcoCover(3, gobco4): + case GobcoCover(3, gobco4 == true): // begin int-2D _ = 1 // end int-2D - case GobcoCover(4, gobco5): + case GobcoCover(4, gobco5 == true): // begin int-1D _ = 1 } diff --git a/testdata/instrumenter/CompositeLit.cond b/testdata/instrumenter/CompositeLit.cond index 55ec2a4..448a152 100644 --- a/testdata/instrumenter/CompositeLit.cond +++ b/testdata/instrumenter/CompositeLit.cond @@ -10,13 +10,13 @@ func compositeLit(i int) { // Both keys and values are instrumented in condition coverage mode. _ = map[bool]bool{ - GobcoCover(0, i > 0): GobcoCover(1, i > 1), + GobcoCover(0, i > 0) == true: GobcoCover(1, i > 1) == true, } // Nested values are instrumented in condition coverage mode. _ = [][]bool{ - {GobcoCover(2, i > 2)}, - {GobcoCover(3, i > 3)}, + {GobcoCover(2, i > 2) == true}, + {GobcoCover(3, i > 3) == true}, } } diff --git a/testdata/instrumenter/DeferStmt.cond b/testdata/instrumenter/DeferStmt.cond index 455c191..87cbe4f 100644 --- a/testdata/instrumenter/DeferStmt.cond +++ b/testdata/instrumenter/DeferStmt.cond @@ -9,7 +9,7 @@ package instrumenter // // Defer statements are not instrumented themselves. func deferStmt() { - defer func(args ...interface{}) {}(1, GobcoCover(0, 1 > 0), !GobcoCover(1, false)) + defer func(args ...interface{}) {}(1, GobcoCover(0, 1 > 0) == true, !(GobcoCover(1, false == true) == true)) } // :12:40: "1 > 0" diff --git a/testdata/instrumenter/ExprStmt.cond b/testdata/instrumenter/ExprStmt.cond index f3eed68..667d518 100644 --- a/testdata/instrumenter/ExprStmt.cond +++ b/testdata/instrumenter/ExprStmt.cond @@ -11,15 +11,15 @@ func exprStmt(i int, ch map[bool]<-chan int) { f := func(bool) {} // Statement expressions may be parenthesized. - f(GobcoCover(0, i > 0)) - (f(GobcoCover(1, i > 1))) - (f)(GobcoCover(2, i > 2)) - ((f)(GobcoCover(3, i > 3))) + f(GobcoCover(0, i > 0) == true) + (f(GobcoCover(1, i > 1) == true)) + (f)(GobcoCover(2, i > 2) == true) + ((f)(GobcoCover(3, i > 3) == true)) - <-ch[GobcoCover(4, i > 10)] - (<-ch[GobcoCover(5, i > 11)]) - <-(ch[GobcoCover(6, i > 12)]) - (<-(ch[GobcoCover(7, i > 13)])) + <-ch[GobcoCover(4, i > 10) == true] + (<-ch[GobcoCover(5, i > 11) == true]) + <-(ch[GobcoCover(6, i > 12) == true]) + (<-(ch[GobcoCover(7, i > 13) == true])) } // :14:4: "i > 0" diff --git a/testdata/instrumenter/ForStmt.branch b/testdata/instrumenter/ForStmt.branch index e7a3fe1..89da1f8 100644 --- a/testdata/instrumenter/ForStmt.branch +++ b/testdata/instrumenter/ForStmt.branch @@ -13,21 +13,21 @@ func forStmt(a byte, b string) bool { // The condition of a ForStmt, if present, is always a boolean // expression and is therefore instrumented, no matter if it is a // simple or a complex expression. - for i := 0; GobcoCover(0, i < len(b)); i++ { - if GobcoCover(1, b[i] == a) { + for i := 0; GobcoCover(0, i < len(b)) == true; i++ { + if GobcoCover(1, b[i] == a) == true { return true } } // The condition of a ForStmt can be a single identifier. tooSmall := true - for i := 0; GobcoCover(2, tooSmall); i++ { + for i := 0; GobcoCover(2, tooSmall == true) == true; i++ { tooSmall = i < 5 } // The condition of a ForStmt can be a complex condition. bigEnough := false - for i := 0; GobcoCover(3, !bigEnough); i++ { + for i := 0; GobcoCover(3, !bigEnough) == true; i++ { bigEnough = i >= 5 } diff --git a/testdata/instrumenter/ForStmt.cond b/testdata/instrumenter/ForStmt.cond index 4ef6cb1..c47eaae 100644 --- a/testdata/instrumenter/ForStmt.cond +++ b/testdata/instrumenter/ForStmt.cond @@ -13,22 +13,22 @@ func forStmt(a byte, b string) bool { // The condition of a ForStmt, if present, is always a boolean // expression and is therefore instrumented, no matter if it is a // simple or a complex expression. - for i := 0; GobcoCover(0, i < len(b)); i++ { - if GobcoCover(1, b[i] == a) { + for i := 0; GobcoCover(0, i < len(b)) == true; i++ { + if GobcoCover(1, b[i] == a) == true { return true } } // The condition of a ForStmt can be a single identifier. tooSmall := true - for i := 0; GobcoCover(2, tooSmall); i++ { - tooSmall = GobcoCover(3, i < 5) + for i := 0; GobcoCover(2, tooSmall == true) == true; i++ { + tooSmall = GobcoCover(3, i < 5) == true } // The condition of a ForStmt can be a complex condition. bigEnough := false - for i := 0; !GobcoCover(4, bigEnough); i++ { - bigEnough = GobcoCover(5, i >= 5) + for i := 0; !(GobcoCover(4, bigEnough == true) == true); i++ { + bigEnough = GobcoCover(5, i >= 5) == true } return false diff --git a/testdata/instrumenter/FuncDecl.cond b/testdata/instrumenter/FuncDecl.cond index 2220e03..da42735 100644 --- a/testdata/instrumenter/FuncDecl.cond +++ b/testdata/instrumenter/FuncDecl.cond @@ -14,7 +14,7 @@ func funcDecl() { // expression in a temporary variable with a generated name that // is unlikely to conflict with any actually used variable. { - gobco0 := GobcoCover(0, 1 > 0) + gobco0 := GobcoCover(0, 1 > 0) == true _ = gobco0 switch { } @@ -26,7 +26,7 @@ func funcDecl2() { // The names of the temporary variables are unique per top-level // function declaration. { - gobco0 := GobcoCover(1, 2 > 0) + gobco0 := GobcoCover(1, 2 > 0) == true _ = gobco0 switch { default: @@ -34,7 +34,7 @@ func funcDecl2() { // so the counter for variable names is not reset here. _ = func() { { - gobco1 := GobcoCover(2, 3 > 0) + gobco1 := GobcoCover(2, 3 > 0) == true _ = gobco1 switch { } diff --git a/testdata/instrumenter/FuncLit.branch b/testdata/instrumenter/FuncLit.branch index d70d982..b943e5c 100644 --- a/testdata/instrumenter/FuncLit.branch +++ b/testdata/instrumenter/FuncLit.branch @@ -14,7 +14,7 @@ func funcLit() { inner(-3) // Function literals are typically larger than other expressions. - if GobcoCover(0, func() int { return 3 }() > 2) { + if GobcoCover(0, func() int { return 3 }() > 2) == true { } // Function literals can span multiple lines. @@ -22,7 +22,7 @@ func funcLit() { // line breaks. if GobcoCover(1, func() int { return 3 - }() > 2) { + }() > 2) == true { } } diff --git a/testdata/instrumenter/FuncLit.cond b/testdata/instrumenter/FuncLit.cond index 1c7de9d..4f5f07c 100644 --- a/testdata/instrumenter/FuncLit.cond +++ b/testdata/instrumenter/FuncLit.cond @@ -8,13 +8,13 @@ package instrumenter // Function literal expressions are not instrumented themselves. func funcLit() { inner := func(i int) bool { - return GobcoCover(0, i > 0) + return GobcoCover(0, i > 0) == true } inner(3) inner(-3) // Function literals are typically larger than other expressions. - if GobcoCover(1, func() int { return 3 }() > 2) { + if GobcoCover(1, func() int { return 3 }() > 2) == true { } // Function literals can span multiple lines. @@ -22,7 +22,7 @@ func funcLit() { // line breaks. if GobcoCover(2, func() int { return 3 - }() > 2) { + }() > 2) == true { } } diff --git a/testdata/instrumenter/GoStmt.cond b/testdata/instrumenter/GoStmt.cond index 5be0a4b..d05fd3e 100644 --- a/testdata/instrumenter/GoStmt.cond +++ b/testdata/instrumenter/GoStmt.cond @@ -9,7 +9,7 @@ package instrumenter // // Go statements are not instrumented themselves. func goStmt() { - go func(args ...interface{}) {}(1, GobcoCover(0, 1 > 0), !GobcoCover(1, false)) + go func(args ...interface{}) {}(1, GobcoCover(0, 1 > 0) == true, !(GobcoCover(1, false == true) == true)) } // :12:37: "1 > 0" diff --git a/testdata/instrumenter/IfStmt.branch b/testdata/instrumenter/IfStmt.branch index d8a1817..f8e1bf4 100644 --- a/testdata/instrumenter/IfStmt.branch +++ b/testdata/instrumenter/IfStmt.branch @@ -13,12 +13,12 @@ import "fmt" // In branch coverage mode, the main condition is instrumented. func ifStmt(i int, s string, cond bool) string { - if GobcoCover(0, i > 0 && s == "positive") { + if GobcoCover(0, i > 0 && s == "positive") == true { return "yes, positive" } - if GobcoCover(1, len(s) > 5) { - if GobcoCover(2, len(s) > 10) { + if GobcoCover(1, len(s) > 5) == true { + if GobcoCover(2, len(s) > 10) == true { return "long string" } else { return "medium string" @@ -29,7 +29,7 @@ func ifStmt(i int, s string, cond bool) string { // And even if the condition is a simple variable, it is wrapped. // This is different from arguments to function calls, where simple // variables are not wrapped. - if GobcoCover(3, cond) { + if GobcoCover(3, cond == true) == true { return "cond is true" } @@ -39,23 +39,23 @@ func ifStmt(i int, s string, cond bool) string { // instrumentation, so there is no need to introduce a new // variable. Therefore, no complicated rewriting is needed. - if i++; GobcoCover(4, cond) { + if i++; GobcoCover(4, cond == true) == true { return fmt.Sprint("incremented ", i > 5) } - if i := i + 1; GobcoCover(5, cond) { + if i := i + 1; GobcoCover(5, cond == true) == true { return fmt.Sprint("added 1, now ", i > 6) } // Conditions in the initializer are instrumented as well, // but only in condition coverage mode. - if cond := i > 7; GobcoCover(6, cond) { + if cond := i > 7; GobcoCover(6, cond == true) == true { return fmt.Sprint("condition in initializer ", i > 8) } - if GobcoCover(7, i < 21) { + if GobcoCover(7, i < 21) == true { i += 31 - } else if GobcoCover(8, i < 22) { + } else if GobcoCover(8, i < 22) == true { i += 32 } else { i += 33 diff --git a/testdata/instrumenter/IfStmt.cond b/testdata/instrumenter/IfStmt.cond index c9f44e2..180221a 100644 --- a/testdata/instrumenter/IfStmt.cond +++ b/testdata/instrumenter/IfStmt.cond @@ -13,12 +13,12 @@ import "fmt" // In branch coverage mode, the main condition is instrumented. func ifStmt(i int, s string, cond bool) string { - if GobcoCover(0, i > 0) && GobcoCover(1, s == "positive") { + if GobcoCover(0, i > 0) == true && GobcoCover(1, s == "positive") == true { return "yes, positive" } - if GobcoCover(2, len(s) > 5) { - if GobcoCover(3, len(s) > 10) { + if GobcoCover(2, len(s) > 5) == true { + if GobcoCover(3, len(s) > 10) == true { return "long string" } else { return "medium string" @@ -29,7 +29,7 @@ func ifStmt(i int, s string, cond bool) string { // And even if the condition is a simple variable, it is wrapped. // This is different from arguments to function calls, where simple // variables are not wrapped. - if GobcoCover(4, cond) { + if GobcoCover(4, cond == true) == true { return "cond is true" } @@ -39,23 +39,23 @@ func ifStmt(i int, s string, cond bool) string { // instrumentation, so there is no need to introduce a new // variable. Therefore, no complicated rewriting is needed. - if i++; GobcoCover(5, cond) { - return fmt.Sprint("incremented ", GobcoCover(6, i > 5)) + if i++; GobcoCover(5, cond == true) == true { + return fmt.Sprint("incremented ", GobcoCover(6, i > 5) == true) } - if i := i + 1; GobcoCover(7, cond) { - return fmt.Sprint("added 1, now ", GobcoCover(8, i > 6)) + if i := i + 1; GobcoCover(7, cond == true) == true { + return fmt.Sprint("added 1, now ", GobcoCover(8, i > 6) == true) } // Conditions in the initializer are instrumented as well, // but only in condition coverage mode. - if cond := GobcoCover(9, i > 7); GobcoCover(10, cond) { - return fmt.Sprint("condition in initializer ", GobcoCover(11, i > 8)) + if cond := GobcoCover(9, i > 7) == true; GobcoCover(10, cond == true) == true { + return fmt.Sprint("condition in initializer ", GobcoCover(11, i > 8) == true) } - if GobcoCover(12, i < 21) { + if GobcoCover(12, i < 21) == true { i += 31 - } else if GobcoCover(13, i < 22) { + } else if GobcoCover(13, i < 22) == true { i += 32 } else { i += 33 diff --git a/testdata/instrumenter/IncDecStmt.cond b/testdata/instrumenter/IncDecStmt.cond index a76c76f..8604ba6 100644 --- a/testdata/instrumenter/IncDecStmt.cond +++ b/testdata/instrumenter/IncDecStmt.cond @@ -19,10 +19,10 @@ func incDecStmt() { // ... or a map index expression. m := map[bool]int{} - m[!GobcoCover(0, true)]++ - m[!GobcoCover(1, false)]-- - m[GobcoCover(2, i == 11)]++ - m[GobcoCover(3, i == 12)]-- + m[!(GobcoCover(0, true == true) == true)]++ + m[!(GobcoCover(1, false == true) == true)]-- + m[GobcoCover(2, i == 11) == true]++ + m[GobcoCover(3, i == 12) == true]-- } // :22:5: "true" diff --git a/testdata/instrumenter/IndexExpr.cond b/testdata/instrumenter/IndexExpr.cond index de7c83a..3b7a516 100644 --- a/testdata/instrumenter/IndexExpr.cond +++ b/testdata/instrumenter/IndexExpr.cond @@ -14,14 +14,14 @@ func indexExpr(i int, cond bool) { // This index expression is instrumented in condition coverage mode, // as its type must be bool. - m[GobcoCover(0, i > 0)] = "yes" + m[GobcoCover(0, i > 0) == true] = "yes" // This index expression is not instrumented, as gobco doesn't resolve // types. m[cond] = "cond" // Both index expressions are instrumented in condition coverage mode. - mm[GobcoCover(1, i > 1)][GobcoCover(2, i > 2)] = "both" + mm[GobcoCover(1, i > 1) == true][GobcoCover(2, i > 2) == true] = "both" } // :17:4: "i > 0" diff --git a/testdata/instrumenter/RangeStmt.branch b/testdata/instrumenter/RangeStmt.branch index 1a83485..e94f20b 100644 --- a/testdata/instrumenter/RangeStmt.branch +++ b/testdata/instrumenter/RangeStmt.branch @@ -24,7 +24,7 @@ func rangeStmt(i int) bool { // manually add a condition before the range statement: // _ = len(ms[i > 10]) > 0 for _, r := range ms[i > 10] { - if GobcoCover(0, r == mr[i > 11]) { + if GobcoCover(0, r == mr[i > 11]) == true { return true } } diff --git a/testdata/instrumenter/RangeStmt.cond b/testdata/instrumenter/RangeStmt.cond index 741e68c..d1929ee 100644 --- a/testdata/instrumenter/RangeStmt.cond +++ b/testdata/instrumenter/RangeStmt.cond @@ -23,15 +23,15 @@ func rangeStmt(i int) bool { // Code that wants to have this check in a specific place can just // manually add a condition before the range statement: // _ = len(ms[i > 10]) > 0 - for _, r := range ms[GobcoCover(0, i > 10)] { - if GobcoCover(1, r == mr[GobcoCover(2, i > 11)]) { + for _, r := range ms[GobcoCover(0, i > 10) == true] { + if GobcoCover(1, r == mr[GobcoCover(2, i > 11) == true]) == true { return true } } // In a range loop using '=', the expressions on the left don't need // to be plain identifiers. - for mi[GobcoCover(3, i > 10)], mr[GobcoCover(4, i > 11)] = range ms[GobcoCover(5, i > 12)] { + for mi[GobcoCover(3, i > 10) == true], mr[GobcoCover(4, i > 11) == true] = range ms[GobcoCover(5, i > 12) == true] { } return false diff --git a/testdata/instrumenter/SelectorExpr.cond b/testdata/instrumenter/SelectorExpr.cond index 50dfd53..e840c64 100644 --- a/testdata/instrumenter/SelectorExpr.cond +++ b/testdata/instrumenter/SelectorExpr.cond @@ -12,7 +12,7 @@ package instrumenter func selectorExpr() { m := map[bool]struct{ a string }{true: {""}} - _ = m[GobcoCover(0, 1 > 0)].a + _ = m[GobcoCover(0, 1 > 0) == true].a } // :15:8: "1 > 0" diff --git a/testdata/instrumenter/SendStmt.cond b/testdata/instrumenter/SendStmt.cond index 9fac265..42b2c49 100644 --- a/testdata/instrumenter/SendStmt.cond +++ b/testdata/instrumenter/SendStmt.cond @@ -11,7 +11,7 @@ package instrumenter func sendStmt(i int) { m := map[bool]chan bool{} - m[GobcoCover(0, i == 11)] <- GobcoCover(1, i == 12) + m[GobcoCover(0, i == 11) == true] <- GobcoCover(1, i == 12) == true } // :14:4: "i == 11" diff --git a/testdata/instrumenter/SliceExpr.cond b/testdata/instrumenter/SliceExpr.cond index 5d07858..59307c1 100644 --- a/testdata/instrumenter/SliceExpr.cond +++ b/testdata/instrumenter/SliceExpr.cond @@ -13,9 +13,9 @@ func sliceExpr() { ms := map[bool][]int{} var slice []int - _ = slice[m[GobcoCover(0, 11 == 0)]:] - _ = slice[:m[GobcoCover(1, 21 == 0)]] - _ = ms[GobcoCover(2, 30 == 0)][m[GobcoCover(3, 31 == 0)]:m[GobcoCover(4, 32 == 0)]:m[GobcoCover(5, 33 == 0)]] + _ = slice[m[GobcoCover(0, 11 == 0) == true]:] + _ = slice[:m[GobcoCover(1, 21 == 0) == true]] + _ = ms[GobcoCover(2, 30 == 0) == true][m[GobcoCover(3, 31 == 0) == true]:m[GobcoCover(4, 32 == 0) == true]:m[GobcoCover(5, 33 == 0) == true]] // A slice can only occur in a comparison if it is compared to nil. // In that case, it doesn't need to be parenthesized when generating diff --git a/testdata/instrumenter/StarExpr.cond b/testdata/instrumenter/StarExpr.cond index 1c1c2bb..9c8dce3 100644 --- a/testdata/instrumenter/StarExpr.cond +++ b/testdata/instrumenter/StarExpr.cond @@ -12,7 +12,7 @@ package instrumenter func starExpr() { m := map[bool]*int{} - _ = *m[GobcoCover(0, 11 == 0)] + _ = *m[GobcoCover(0, 11 == 0) == true] } // :15:9: "11 == 0" diff --git a/testdata/instrumenter/SwitchStmt.branch b/testdata/instrumenter/SwitchStmt.branch index 08312f9..c6740d7 100644 --- a/testdata/instrumenter/SwitchStmt.branch +++ b/testdata/instrumenter/SwitchStmt.branch @@ -15,7 +15,7 @@ func switchStmt(expr int, cond bool, s string) { // therefore they are instrumented. switch { case GobcoCover(0, expr == 5): - case GobcoCover(1, cond): + case GobcoCover(1, cond == true): } // No matter whether there is an init statement or not, if the tag @@ -23,14 +23,14 @@ func switchStmt(expr int, cond bool, s string) { // compared to an explicit "true". switch s := "prefix" + s; { case GobcoCover(2, s == "one"): - case GobcoCover(3, cond): + case GobcoCover(3, cond == true): } // In a switch statement without tag expression, ensure that complex // conditions in the case clauses are not instrumented redundantly. switch a, b := cond, !cond; { - case (GobcoCover(4, a && b)): - case (GobcoCover(5, a || b)): + case (GobcoCover(4, a && b) == true): + case (GobcoCover(5, a || b) == true): } // No initialization, the tag is a plain identifier. diff --git a/testdata/instrumenter/SwitchStmt.cond b/testdata/instrumenter/SwitchStmt.cond index 2aa6885..698765c 100644 --- a/testdata/instrumenter/SwitchStmt.cond +++ b/testdata/instrumenter/SwitchStmt.cond @@ -15,7 +15,7 @@ func switchStmt(expr int, cond bool, s string) { // therefore they are instrumented. switch { case GobcoCover(0, expr == 5): - case GobcoCover(1, cond): + case GobcoCover(1, cond == true): } // No matter whether there is an init statement or not, if the tag @@ -23,14 +23,14 @@ func switchStmt(expr int, cond bool, s string) { // compared to an explicit "true". switch s := "prefix" + s; { case GobcoCover(2, s == "one"): - case GobcoCover(3, cond): + case GobcoCover(3, cond == true): } // In a switch statement without tag expression, ensure that complex // conditions in the case clauses are not instrumented redundantly. - switch a, b := cond, !GobcoCover(4, cond); { - case (GobcoCover(5, a) && GobcoCover(6, b)): - case (GobcoCover(7, a) || GobcoCover(8, b)): + switch a, b := cond, !(GobcoCover(4, cond == true) == true); { + case (GobcoCover(5, a == true) == true && GobcoCover(6, b == true) == true): + case (GobcoCover(7, a == true) == true || GobcoCover(8, b == true) == true): } // No initialization, the tag is a plain identifier. @@ -111,16 +111,16 @@ func switchStmt(expr int, cond bool, s string) { // The crucial point is that it's not the value of 'a' alone that // decides which branch is taken, but instead 'cond == a'. { - a, b := cond, !GobcoCover(19, cond) + a, b := cond, !(GobcoCover(19, cond == true) == true) gobco6 := cond switch { case GobcoCover(20, gobco6 == a): - case GobcoCover(21, gobco6 == !GobcoCover(22, a)): - case GobcoCover(23, gobco6 == (!GobcoCover(24, a))): - case GobcoCover(25, gobco6 == (GobcoCover(26, a) && GobcoCover(27, b))): - case GobcoCover(28, gobco6 == (GobcoCover(29, a) && !GobcoCover(30, b))): - case GobcoCover(31, gobco6 == (GobcoCover(32, a) || GobcoCover(33, b))): - case GobcoCover(34, gobco6 == (!GobcoCover(35, a) || GobcoCover(36, b))): + case GobcoCover(21, gobco6 == !(GobcoCover(22, a == true) == true)): + case GobcoCover(23, gobco6 == (!(GobcoCover(24, a == true) == true))): + case GobcoCover(25, gobco6 == (GobcoCover(26, a == true) == true && GobcoCover(27, b == true) == true)): + case GobcoCover(28, gobco6 == (GobcoCover(29, a == true) == true && !(GobcoCover(30, b == true) == true))): + case GobcoCover(31, gobco6 == (GobcoCover(32, a == true) == true || GobcoCover(33, b == true) == true)): + case GobcoCover(34, gobco6 == (!(GobcoCover(35, a == true) == true) || GobcoCover(36, b == true) == true)): case GobcoCover(37, gobco6 == (a == b)): case GobcoCover(38, gobco6 == (a != b)): } @@ -128,7 +128,7 @@ func switchStmt(expr int, cond bool, s string) { // In a switch statement, the tag expression may be unused. { - gobco7 := GobcoCover(39, 1 > 0) + gobco7 := GobcoCover(39, 1 > 0) == true _ = gobco7 switch { } diff --git a/testdata/instrumenter/TypeAssertExpr.cond b/testdata/instrumenter/TypeAssertExpr.cond index 2502f97..2dd6864 100644 --- a/testdata/instrumenter/TypeAssertExpr.cond +++ b/testdata/instrumenter/TypeAssertExpr.cond @@ -12,7 +12,7 @@ package instrumenter func typeAssertExpr() { m := map[bool]interface{}{} - _ = m[GobcoCover(0, 11 != 0)].(int) + _ = m[GobcoCover(0, 11 != 0) == true].(int) } // :15:8: "11 != 0" diff --git a/testdata/instrumenter/TypeSwitchStmt.branch b/testdata/instrumenter/TypeSwitchStmt.branch index ebe0e13..98ed413 100644 --- a/testdata/instrumenter/TypeSwitchStmt.branch +++ b/testdata/instrumenter/TypeSwitchStmt.branch @@ -60,7 +60,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { gobco2 := tag _, gobco3 := gobco2.((int)) switch { - case GobcoCover(0, gobco3): + case GobcoCover(0, gobco3 == true): return "parenthesized " + reflect.TypeOf(tag).Name() } } @@ -70,7 +70,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { gobco4 := tag gobco5 := gobco4 == nil switch { - case GobcoCover(1, gobco5): + case GobcoCover(1, gobco5 == true): return "parenthesized nil" } } @@ -85,18 +85,18 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { _, gobco9 := gobco6.(uint16) gobco10 := gobco6 == nil switch { - case GobcoCover(2, gobco7): + case GobcoCover(2, gobco7 == true): v := gobco6.(uint) _ = v _ = v + uint(0) return "uint " + reflect.TypeOf(v).Name() - case GobcoCover(3, gobco8), GobcoCover(4, gobco9): + case GobcoCover(3, gobco8 == true), GobcoCover(4, gobco9 == true): v := gobco6 _ = v return "any " + reflect.TypeOf(v).Name() - case GobcoCover(5, gobco10): + case GobcoCover(5, gobco10 == true): v := gobco6 _ = v @@ -126,7 +126,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { _, gobco25 := gobco11.(*int) switch { - case GobcoCover(6, gobco12), GobcoCover(7, gobco13): + case GobcoCover(6, gobco12 == true), GobcoCover(7, gobco13 == true): v := gobco11 _ = v @@ -134,7 +134,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { // type of the switch tag, in this case 'interface{}'. return "integer " + reflect.TypeOf(v).String() - case GobcoCover(8, gobco14): + case GobcoCover(8, gobco14 == true): v := gobco11.(string) _ = v @@ -142,68 +142,68 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { // type from the case clause. return "string " + reflect.TypeOf(v).String() - case GobcoCover(9, gobco15): + case GobcoCover(9, gobco15 == true): v := gobco11.(struct{}) _ = v return "struct{} " + reflect.TypeOf(v).String() - case GobcoCover(10, gobco16): + case GobcoCover(10, gobco16 == true): v := gobco11.(uint8) _ = v // The variable 'v' may be unused in some of the case clauses. return "byte" - case GobcoCover(11, gobco17): + case GobcoCover(11, gobco17 == true): v := gobco11 _ = v return "nil" - case GobcoCover(12, gobco18): + case GobcoCover(12, gobco18 == true): v := gobco11.([3]int) _ = v return "array of int" - case GobcoCover(13, gobco19): + case GobcoCover(13, gobco19 == true): v := gobco11.([]int) _ = v return "slice of int" - case GobcoCover(14, gobco20): + case GobcoCover(14, gobco20 == true): v := gobco11.(struct{ field int }) _ = v return "struct with field" - case GobcoCover(15, gobco21): + case GobcoCover(15, gobco21 == true): v := gobco11.(func(int) int) _ = v return "function taking int and returning int" - case GobcoCover(16, gobco22): + case GobcoCover(16, gobco22 == true): v := gobco11.(interface{ ReadByte() (byte, error) }) _ = v return "interface with ReadByte" - case GobcoCover(17, gobco23): + case GobcoCover(17, gobco23 == true): v := gobco11.(map[int]int) _ = v return "map from int to int" - case GobcoCover(18, gobco24): + case GobcoCover(18, gobco24 == true): v := gobco11.(chan int) _ = v return "chan of int" - case GobcoCover(19, gobco25): + case GobcoCover(19, gobco25 == true): v := gobco11.(*int) _ = v @@ -230,9 +230,9 @@ func typeSwitchStmtMixed(value interface{}) { _, gobco1 := gobco0.(int) _, gobco2 := gobco0.(uint) switch { - case GobcoCover(20, gobco1): + case GobcoCover(20, gobco1 == true): _ = true && false - case GobcoCover(21, gobco2): + case GobcoCover(21, gobco2 == true): _ = false || true } } @@ -250,7 +250,7 @@ func typeSwitchStmtNested() { gobco0 := interface{}(3) _, gobco1 := gobco0.(uint8) switch { - case GobcoCover(22, gobco1): + case GobcoCover(22, gobco1 == true): default: { gobco2 := 1 + 1 diff --git a/testdata/instrumenter/TypeSwitchStmt.cond b/testdata/instrumenter/TypeSwitchStmt.cond index 509882b..b4c3f64 100644 --- a/testdata/instrumenter/TypeSwitchStmt.cond +++ b/testdata/instrumenter/TypeSwitchStmt.cond @@ -60,7 +60,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { gobco2 := tag _, gobco3 := gobco2.((int)) switch { - case GobcoCover(0, gobco3): + case GobcoCover(0, gobco3 == true): return "parenthesized " + reflect.TypeOf(tag).Name() } } @@ -70,7 +70,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { gobco4 := tag gobco5 := gobco4 == nil switch { - case GobcoCover(1, gobco5): + case GobcoCover(1, gobco5 == true): return "parenthesized nil" } } @@ -85,18 +85,18 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { _, gobco9 := gobco6.(uint16) gobco10 := gobco6 == nil switch { - case GobcoCover(2, gobco7): + case GobcoCover(2, gobco7 == true): v := gobco6.(uint) _ = v _ = v + uint(0) return "uint " + reflect.TypeOf(v).Name() - case GobcoCover(3, gobco8), GobcoCover(4, gobco9): + case GobcoCover(3, gobco8 == true), GobcoCover(4, gobco9 == true): v := gobco6 _ = v return "any " + reflect.TypeOf(v).Name() - case GobcoCover(5, gobco10): + case GobcoCover(5, gobco10 == true): v := gobco6 _ = v @@ -108,7 +108,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { // TODO: Test type parameters and generic types. { - _ = GobcoCover(23, 123 > 0) + _ = GobcoCover(23, 123 > 0) == true gobco11 := value _, gobco12 := gobco11.(int) _, gobco13 := gobco11.(uint) @@ -126,7 +126,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { _, gobco25 := gobco11.(*int) switch { - case GobcoCover(6, gobco12), GobcoCover(7, gobco13): + case GobcoCover(6, gobco12 == true), GobcoCover(7, gobco13 == true): v := gobco11 _ = v @@ -134,7 +134,7 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { // type of the switch tag, in this case 'interface{}'. return "integer " + reflect.TypeOf(v).String() - case GobcoCover(8, gobco14): + case GobcoCover(8, gobco14 == true): v := gobco11.(string) _ = v @@ -142,68 +142,68 @@ func typeSwitchStmt(tag interface{}, value interface{}) string { // type from the case clause. return "string " + reflect.TypeOf(v).String() - case GobcoCover(9, gobco15): + case GobcoCover(9, gobco15 == true): v := gobco11.(struct{}) _ = v return "struct{} " + reflect.TypeOf(v).String() - case GobcoCover(10, gobco16): + case GobcoCover(10, gobco16 == true): v := gobco11.(uint8) _ = v // The variable 'v' may be unused in some of the case clauses. return "byte" - case GobcoCover(11, gobco17): + case GobcoCover(11, gobco17 == true): v := gobco11 _ = v return "nil" - case GobcoCover(12, gobco18): + case GobcoCover(12, gobco18 == true): v := gobco11.([3]int) _ = v return "array of int" - case GobcoCover(13, gobco19): + case GobcoCover(13, gobco19 == true): v := gobco11.([]int) _ = v return "slice of int" - case GobcoCover(14, gobco20): + case GobcoCover(14, gobco20 == true): v := gobco11.(struct{ field int }) _ = v return "struct with field" - case GobcoCover(15, gobco21): + case GobcoCover(15, gobco21 == true): v := gobco11.(func(int) int) _ = v return "function taking int and returning int" - case GobcoCover(16, gobco22): + case GobcoCover(16, gobco22 == true): v := gobco11.(interface{ ReadByte() (byte, error) }) _ = v return "interface with ReadByte" - case GobcoCover(17, gobco23): + case GobcoCover(17, gobco23 == true): v := gobco11.(map[int]int) _ = v return "map from int to int" - case GobcoCover(18, gobco24): + case GobcoCover(18, gobco24 == true): v := gobco11.(chan int) _ = v return "chan of int" - case GobcoCover(19, gobco25): + case GobcoCover(19, gobco25 == true): v := gobco11.(*int) _ = v @@ -230,10 +230,10 @@ func typeSwitchStmtMixed(value interface{}) { _, gobco1 := gobco0.(int) _, gobco2 := gobco0.(uint) switch { - case GobcoCover(20, gobco1): - _ = GobcoCover(24, true) && GobcoCover(25, false) - case GobcoCover(21, gobco2): - _ = GobcoCover(26, false) || GobcoCover(27, true) + case GobcoCover(20, gobco1 == true): + _ = GobcoCover(24, true == true) == true && GobcoCover(25, false == true) == true + case GobcoCover(21, gobco2 == true): + _ = GobcoCover(26, false == true) == true || GobcoCover(27, true == true) == true } } @@ -250,7 +250,7 @@ func typeSwitchStmtNested() { gobco0 := interface{}(3) _, gobco1 := gobco0.(uint8) switch { - case GobcoCover(22, gobco1): + case GobcoCover(22, gobco1 == true): default: { gobco2 := 1 + 1 diff --git a/testdata/instrumenter/UnaryExpr.branch b/testdata/instrumenter/UnaryExpr.branch index bcb774d..e35744b 100644 --- a/testdata/instrumenter/UnaryExpr.branch +++ b/testdata/instrumenter/UnaryExpr.branch @@ -17,7 +17,7 @@ func unaryExpr(a, b, c bool, i int) { _ = !!!a _ = !b && c - if GobcoCover(0, -i > 0) { + if GobcoCover(0, -i > 0) == true { } // In double negations, only the terminal condition is instrumented. diff --git a/testdata/instrumenter/UnaryExpr.cond b/testdata/instrumenter/UnaryExpr.cond index 0187218..fbb9ede 100644 --- a/testdata/instrumenter/UnaryExpr.cond +++ b/testdata/instrumenter/UnaryExpr.cond @@ -14,14 +14,14 @@ package instrumenter func unaryExpr(a, b, c bool, i int) { // To avoid double negation, only the innermost expression of a // negation is instrumented. - _ = !!!GobcoCover(0, a) - _ = !GobcoCover(1, b) && GobcoCover(2, c) + _ = !!!(GobcoCover(0, a == true) == true) + _ = !(GobcoCover(1, b == true) == true) && GobcoCover(2, c == true) == true - if GobcoCover(3, -i > 0) { + if GobcoCover(3, -i > 0) == true { } // In double negations, only the terminal condition is instrumented. - _ = !(!GobcoCover(4, a)) + _ = !(!(GobcoCover(4, a == true) == true)) } // :17:9: "a" diff --git a/testdata/instrumenter/ValueSpec.cond b/testdata/instrumenter/ValueSpec.cond index 7a7fd84..cb5075a 100644 --- a/testdata/instrumenter/ValueSpec.cond +++ b/testdata/instrumenter/ValueSpec.cond @@ -11,8 +11,8 @@ package instrumenter // Value specifications are not instrumented themselves. func valueSpec() { var ( - _ = GobcoCover(0, 1 > 0) - _ = GobcoCover(1, 0 > 1) + _ = GobcoCover(0, 1 > 0) == true + _ = GobcoCover(1, 0 > 1) == true ) // Do not instrument constant expressions. @@ -26,9 +26,9 @@ func valueSpec() { // https://go.dev/ref/spec#Package_initialization var ( - third = GobcoCover(2, second) && GobcoCover(3, 3 > 0) - second = !GobcoCover(4, first) - first = GobcoCover(5, 1 > 0) + third = GobcoCover(2, second == true) == true && GobcoCover(3, 3 > 0) == true + second = !(GobcoCover(4, first == true) == true) + first = GobcoCover(5, 1 > 0) == true ) // :14:7: "1 > 0"