From c779628d65d906060a998dc805c44579faba21bb Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Mon, 29 Oct 2018 16:10:42 -0400 Subject: [PATCH] go/ssa: convert the objlookup tests to the new marker syntax Change-Id: I5df3a3cc3d3ab236a6ad964914393a2ccb29803b Reviewed-on: https://go-review.googlesource.com/c/145637 Run-TryBot: Ian Cottrell Run-TryBot: Michael Matloob TryBot-Result: Gobot Gobot Reviewed-by: Michael Matloob --- go/ssa/source_test.go | 54 ++++++++++--- go/ssa/testdata/objlookup.go | 150 +++++++++++++++++------------------ 2 files changed, 116 insertions(+), 88 deletions(-) diff --git a/go/ssa/source_test.go b/go/ssa/source_test.go index e3e70233..9dc3c663 100644 --- a/go/ssa/source_test.go +++ b/go/ssa/source_test.go @@ -13,8 +13,8 @@ import ( "go/parser" "go/token" "go/types" + "io/ioutil" "os" - "regexp" "runtime" "strings" "testing" @@ -32,10 +32,14 @@ func TestObjValueLookup(t *testing.T) { } conf := loader.Config{ParserMode: parser.ParseComments} - f, err := conf.ParseFile("testdata/objlookup.go", nil) + src, err := ioutil.ReadFile("testdata/objlookup.go") if err != nil { - t.Error(err) - return + t.Fatal(err) + } + readFile := func(filename string) ([]byte, error) { return src, nil } + f, err := conf.ParseFile("testdata/objlookup.go", src) + if err != nil { + t.Fatal(err) } conf.CreateFromFiles("main", f) @@ -43,16 +47,40 @@ func TestObjValueLookup(t *testing.T) { // kind of ssa.Value we expect (represented "Constant", "&Alloc"). expectations := make(map[string]string) - // Find all annotations of form x::BinOp, &y::Alloc, etc. - re := regexp.MustCompile(`(\b|&)?(\w*)::(\w*)\b`) - for _, c := range f.Comments { - text := c.Text() - pos := conf.Fset.Position(c.Pos()) - for _, m := range re.FindAllStringSubmatch(text, -1) { - key := fmt.Sprintf("%s:%d", m[2], pos.Line) - value := m[1] + m[3] - expectations[key] = value + // Each note of the form @ssa(x, "BinOp") in testdata/objlookup.go + // specifies an expectation that an object named x declared on the + // same line is associated with an an ssa.Value of type *ssa.BinOp. + notes, err := expect.Extract(conf.Fset, f) + if err != nil { + t.Fatal(err) + } + for _, n := range notes { + if n.Name != "ssa" { + t.Errorf("%v: unexpected note type %q, want \"ssa\"", conf.Fset.Position(n.Pos), n.Name) + continue } + if len(n.Args) != 2 { + t.Errorf("%v: ssa has %d args, want 2", conf.Fset.Position(n.Pos), len(n.Args)) + continue + } + ident, ok := n.Args[0].(expect.Identifier) + if !ok { + t.Errorf("%v: got %v for arg 1, want identifier", conf.Fset.Position(n.Pos), n.Args[0]) + continue + } + exp, ok := n.Args[1].(string) + if !ok { + t.Errorf("%v: got %v for arg 2, want string", conf.Fset.Position(n.Pos), n.Args[1]) + continue + } + p, _, err := expect.MatchBefore(conf.Fset, readFile, n.Pos, string(ident)) + if err != nil { + t.Error(err) + continue + } + pos := conf.Fset.Position(p) + key := fmt.Sprintf("%s:%d", ident, pos.Line) + expectations[key] = exp } iprog, err := conf.Load() diff --git a/go/ssa/testdata/objlookup.go b/go/ssa/testdata/objlookup.go index 1aaa417e..d110add6 100644 --- a/go/ssa/testdata/objlookup.go +++ b/go/ssa/testdata/objlookup.go @@ -24,7 +24,7 @@ func (*J) method() {} const globalConst = 0 -var globalVar int // &globalVar::Global +var globalVar int //@ ssa(globalVar,"&Global") func globalFunc() {} @@ -33,128 +33,128 @@ type I interface { } type S struct { - x int // x::nil + x int //@ ssa(x,"nil") } func main() { - print(globalVar) // globalVar::UnOp - globalVar = 1 // globalVar::Const + print(globalVar) //@ ssa(globalVar,"UnOp") + globalVar = 1 //@ ssa(globalVar,"Const") - var v0 int = 1 // v0::Const (simple local value spec) - if v0 > 0 { // v0::Const - v0 = 2 // v0::Const + var v0 int = 1 //@ ssa(v0,"Const") // simple local value spec + if v0 > 0 { //@ ssa(v0,"Const") + v0 = 2 //@ ssa(v0,"Const") } - print(v0) // v0::Phi + print(v0) //@ ssa(v0,"Phi") // v1 is captured and thus implicitly address-taken. - var v1 int = 1 // v1::Const - v1 = 2 // v1::Const - fmt.Println(v1) // v1::UnOp (load) - f := func(param int) { // f::MakeClosure param::Parameter - if y := 1; y > 0 { // y::Const - print(v1, param) // v1::UnOp (load) param::Parameter + var v1 int = 1 //@ ssa(v1,"Const") + v1 = 2 //@ ssa(v1,"Const") + fmt.Println(v1) //@ ssa(v1,"UnOp") // load + f := func(param int) { //@ ssa(f,"MakeClosure"), ssa(param,"Parameter") + if y := 1; y > 0 { //@ ssa(y,"Const") + print(v1, param) //@ ssa(v1,"UnOp") /*load*/, ssa(param,"Parameter") } - param = 2 // param::Const - println(param) // param::Const + param = 2 //@ ssa(param,"Const") + println(param) //@ ssa(param,"Const") } - f(0) // f::MakeClosure + f(0) //@ ssa(f,"MakeClosure") - var v2 int // v2::Const (implicitly zero-initialized local value spec) - print(v2) // v2::Const + var v2 int //@ ssa(v2,"Const") // implicitly zero-initialized local value spec + print(v2) //@ ssa(v2,"Const") - m := make(map[string]int) // m::MakeMap + m := make(map[string]int) //@ ssa(m,"MakeMap") // Local value spec with multi-valued RHS: - var v3, v4 = m[""] // v3::Extract v4::Extract m::MakeMap - print(v3) // v3::Extract - print(v4) // v4::Extract + var v3, v4 = m[""] //@ ssa(v3,"Extract"), ssa(v4,"Extract"), ssa(m,"MakeMap") + print(v3) //@ ssa(v3,"Extract") + print(v4) //@ ssa(v4,"Extract") - v3++ // v3::BinOp (assign with op) - v3 += 2 // v3::BinOp (assign with op) + v3++ //@ ssa(v3,"BinOp") // assign with op + v3 += 2 //@ ssa(v3,"BinOp") // assign with op - v5, v6 := false, "" // v5::Const v6::Const (defining assignment) - print(v5) // v5::Const - print(v6) // v6::Const + v5, v6 := false, "" //@ ssa(v5,"Const"), ssa(v6,"Const") // defining assignment + print(v5) //@ ssa(v5,"Const") + print(v6) //@ ssa(v6,"Const") - var v7 S // &v7::Alloc - v7.x = 1 // &v7::Alloc &x::FieldAddr - print(v7.x) // &v7::Alloc &x::FieldAddr + var v7 S //@ ssa(v7,"&Alloc") + v7.x = 1 //@ ssa(v7,"&Alloc"), ssa(x,"&FieldAddr") + print(v7.x) //@ ssa(v7,"&Alloc"), ssa(x,"&FieldAddr") - var v8 [1]int // &v8::Alloc - v8[0] = 0 // &v8::Alloc - print(v8[:]) // &v8::Alloc - _ = v8[0] // &v8::Alloc - _ = v8[:][0] // &v8::Alloc - v8ptr := &v8 // v8ptr::Alloc &v8::Alloc - _ = v8ptr[0] // v8ptr::Alloc - _ = *v8ptr // v8ptr::Alloc + var v8 [1]int //@ ssa(v8,"&Alloc") + v8[0] = 0 //@ ssa(v8,"&Alloc") + print(v8[:]) //@ ssa(v8,"&Alloc") + _ = v8[0] //@ ssa(v8,"&Alloc") + _ = v8[:][0] //@ ssa(v8,"&Alloc") + v8ptr := &v8 //@ ssa(v8ptr,"Alloc"), ssa(v8,"&Alloc") + _ = v8ptr[0] //@ ssa(v8ptr,"Alloc") + _ = *v8ptr //@ ssa(v8ptr,"Alloc") - v8a := make([]int, 1) // v8a::Slice - v8a[0] = 0 // v8a::Slice - print(v8a[:]) // v8a::Slice + v8a := make([]int, 1) //@ ssa(v8a,"Slice") + v8a[0] = 0 //@ ssa(v8a,"Slice") + print(v8a[:]) //@ ssa(v8a,"Slice") - v9 := S{} // &v9::Alloc + v9 := S{} //@ ssa(v9,"&Alloc") - v10 := &v9 // v10::Alloc &v9::Alloc - _ = v10 // v10::Alloc + v10 := &v9 //@ ssa(v10,"Alloc"), ssa(v9,"&Alloc") + _ = v10 //@ ssa(v10,"Alloc") - var v11 *J = nil // v11::Const - v11.method() // v11::Const + var v11 *J = nil //@ ssa(v11,"Const") + v11.method() //@ ssa(v11,"Const") - var v12 J // &v12::Alloc - v12.method() // &v12::Alloc (implicitly address-taken) + var v12 J //@ ssa(v12,"&Alloc") + v12.method() //@ ssa(v12,"&Alloc") // implicitly address-taken // NB, in the following, 'method' resolves to the *types.Func // of (*J).method, so it doesn't help us locate the specific // ssa.Values here: a bound-method closure and a promotion // wrapper. - _ = v11.method // v11::Const - _ = (*struct{ J }).method // J::nil + _ = v11.method //@ ssa(v11,"Const") + _ = (*struct{ J }).method //@ ssa(J,"nil") // These vars are not optimised away. if false { - v13 := 0 // v13::Const - println(v13) // v13::Const + v13 := 0 //@ ssa(v13,"Const") + println(v13) //@ ssa(v13,"Const") } - switch x := 1; x { // x::Const - case v0: // v0::Phi + switch x := 1; x { //@ ssa(x,"Const") + case v0: //@ ssa(v0,"Phi") } - for k, v := range m { // k::Extract v::Extract m::MakeMap - _ = k // k::Extract - v++ // v::BinOp + for k, v := range m { //@ ssa(k,"Extract"), ssa(v,"Extract"), ssa(m,"MakeMap") + _ = k //@ ssa(k,"Extract") + v++ //@ ssa(v,"BinOp") } - if y := 0; y > 1 { // y::Const y::Const + if y := 0; y > 1 { //@ ssa(y,"Const"), ssa(y,"Const") } - var i interface{} // i::Const (nil interface) - i = 1 // i::MakeInterface - switch i := i.(type) { // i::MakeInterface i::MakeInterface + var i interface{} //@ ssa(i,"Const") // nil interface + i = 1 //@ ssa(i,"MakeInterface") + switch i := i.(type) { //@ ssa(i,"MakeInterface"), ssa(i,"MakeInterface") case int: - println(i) // i::Extract + println(i) //@ ssa(i,"Extract") } - ch := make(chan int) // ch::MakeChan + ch := make(chan int) //@ ssa(ch,"MakeChan") select { - case x := <-ch: // x::UnOp (receive) ch::MakeChan - _ = x // x::UnOp + case x := <-ch: //@ ssa(x,"UnOp") /*receive*/, ssa(ch,"MakeChan") + _ = x //@ ssa(x,"UnOp") } // .Op is an inter-package FieldVal-selection. - var err os.PathError // &err::Alloc - _ = err.Op // &err::Alloc &Op::FieldAddr - _ = &err.Op // &err::Alloc &Op::FieldAddr + var err os.PathError //@ ssa(err,"&Alloc") + _ = err.Op //@ ssa(err,"&Alloc"), ssa(Op,"&FieldAddr") + _ = &err.Op //@ ssa(err,"&Alloc"), ssa(Op,"&FieldAddr") // Exercise corner-cases of lvalues vs rvalues. // (Guessing IsAddr from the 'pointerness' won't cut it here.) type N *N - var n N // n::Const - n1 := n // n1::Const n::Const - n2 := &n1 // n2::Alloc &n1::Alloc - n3 := *n2 // n3::UnOp n2::Alloc - n4 := **n3 // n4::UnOp n3::UnOp - _ = n4 // n4::UnOp + var n N //@ ssa(n,"Const") + n1 := n //@ ssa(n1,"Const"), ssa(n,"Const") + n2 := &n1 //@ ssa(n2,"Alloc"), ssa(n1,"&Alloc") + n3 := *n2 //@ ssa(n3,"UnOp"), ssa(n2,"Alloc") + n4 := **n3 //@ ssa(n4,"UnOp"), ssa(n3,"UnOp") + _ = n4 //@ ssa(n4,"UnOp") }