1
0
mirror of https://github.com/golang/go synced 2024-11-18 21:24:44 -07:00

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 <iancottrell@google.com>
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Ian Cottrell 2018-10-29 16:10:42 -04:00
parent 7529026f5b
commit c779628d65
2 changed files with 116 additions and 88 deletions

View File

@ -13,8 +13,8 @@ import (
"go/parser" "go/parser"
"go/token" "go/token"
"go/types" "go/types"
"io/ioutil"
"os" "os"
"regexp"
"runtime" "runtime"
"strings" "strings"
"testing" "testing"
@ -32,10 +32,14 @@ func TestObjValueLookup(t *testing.T) {
} }
conf := loader.Config{ParserMode: parser.ParseComments} conf := loader.Config{ParserMode: parser.ParseComments}
f, err := conf.ParseFile("testdata/objlookup.go", nil) src, err := ioutil.ReadFile("testdata/objlookup.go")
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
return }
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) conf.CreateFromFiles("main", f)
@ -43,16 +47,40 @@ func TestObjValueLookup(t *testing.T) {
// kind of ssa.Value we expect (represented "Constant", "&Alloc"). // kind of ssa.Value we expect (represented "Constant", "&Alloc").
expectations := make(map[string]string) expectations := make(map[string]string)
// Find all annotations of form x::BinOp, &y::Alloc, etc. // Each note of the form @ssa(x, "BinOp") in testdata/objlookup.go
re := regexp.MustCompile(`(\b|&)?(\w*)::(\w*)\b`) // specifies an expectation that an object named x declared on the
for _, c := range f.Comments { // same line is associated with an an ssa.Value of type *ssa.BinOp.
text := c.Text() notes, err := expect.Extract(conf.Fset, f)
pos := conf.Fset.Position(c.Pos()) if err != nil {
for _, m := range re.FindAllStringSubmatch(text, -1) { t.Fatal(err)
key := fmt.Sprintf("%s:%d", m[2], pos.Line) }
value := m[1] + m[3] for _, n := range notes {
expectations[key] = value 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() iprog, err := conf.Load()

View File

@ -24,7 +24,7 @@ func (*J) method() {}
const globalConst = 0 const globalConst = 0
var globalVar int // &globalVar::Global var globalVar int //@ ssa(globalVar,"&Global")
func globalFunc() {} func globalFunc() {}
@ -33,128 +33,128 @@ type I interface {
} }
type S struct { type S struct {
x int // x::nil x int //@ ssa(x,"nil")
} }
func main() { func main() {
print(globalVar) // globalVar::UnOp print(globalVar) //@ ssa(globalVar,"UnOp")
globalVar = 1 // globalVar::Const globalVar = 1 //@ ssa(globalVar,"Const")
var v0 int = 1 // v0::Const (simple local value spec) var v0 int = 1 //@ ssa(v0,"Const") // simple local value spec
if v0 > 0 { // v0::Const if v0 > 0 { //@ ssa(v0,"Const")
v0 = 2 // v0::Const v0 = 2 //@ ssa(v0,"Const")
} }
print(v0) // v0::Phi print(v0) //@ ssa(v0,"Phi")
// v1 is captured and thus implicitly address-taken. // v1 is captured and thus implicitly address-taken.
var v1 int = 1 // v1::Const var v1 int = 1 //@ ssa(v1,"Const")
v1 = 2 // v1::Const v1 = 2 //@ ssa(v1,"Const")
fmt.Println(v1) // v1::UnOp (load) fmt.Println(v1) //@ ssa(v1,"UnOp") // load
f := func(param int) { // f::MakeClosure param::Parameter f := func(param int) { //@ ssa(f,"MakeClosure"), ssa(param,"Parameter")
if y := 1; y > 0 { // y::Const if y := 1; y > 0 { //@ ssa(y,"Const")
print(v1, param) // v1::UnOp (load) param::Parameter print(v1, param) //@ ssa(v1,"UnOp") /*load*/, ssa(param,"Parameter")
} }
param = 2 // param::Const param = 2 //@ ssa(param,"Const")
println(param) // 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) var v2 int //@ ssa(v2,"Const") // implicitly zero-initialized local value spec
print(v2) // v2::Const 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: // Local value spec with multi-valued RHS:
var v3, v4 = m[""] // v3::Extract v4::Extract m::MakeMap var v3, v4 = m[""] //@ ssa(v3,"Extract"), ssa(v4,"Extract"), ssa(m,"MakeMap")
print(v3) // v3::Extract print(v3) //@ ssa(v3,"Extract")
print(v4) // v4::Extract print(v4) //@ ssa(v4,"Extract")
v3++ // v3::BinOp (assign with op) v3++ //@ ssa(v3,"BinOp") // assign with op
v3 += 2 // v3::BinOp (assign with op) v3 += 2 //@ ssa(v3,"BinOp") // assign with op
v5, v6 := false, "" // v5::Const v6::Const (defining assignment) v5, v6 := false, "" //@ ssa(v5,"Const"), ssa(v6,"Const") // defining assignment
print(v5) // v5::Const print(v5) //@ ssa(v5,"Const")
print(v6) // v6::Const print(v6) //@ ssa(v6,"Const")
var v7 S // &v7::Alloc var v7 S //@ ssa(v7,"&Alloc")
v7.x = 1 // &v7::Alloc &x::FieldAddr v7.x = 1 //@ ssa(v7,"&Alloc"), ssa(x,"&FieldAddr")
print(v7.x) // &v7::Alloc &x::FieldAddr print(v7.x) //@ ssa(v7,"&Alloc"), ssa(x,"&FieldAddr")
var v8 [1]int // &v8::Alloc var v8 [1]int //@ ssa(v8,"&Alloc")
v8[0] = 0 // &v8::Alloc v8[0] = 0 //@ ssa(v8,"&Alloc")
print(v8[:]) // &v8::Alloc print(v8[:]) //@ ssa(v8,"&Alloc")
_ = v8[0] // &v8::Alloc _ = v8[0] //@ ssa(v8,"&Alloc")
_ = v8[:][0] // &v8::Alloc _ = v8[:][0] //@ ssa(v8,"&Alloc")
v8ptr := &v8 // v8ptr::Alloc &v8::Alloc v8ptr := &v8 //@ ssa(v8ptr,"Alloc"), ssa(v8,"&Alloc")
_ = v8ptr[0] // v8ptr::Alloc _ = v8ptr[0] //@ ssa(v8ptr,"Alloc")
_ = *v8ptr // v8ptr::Alloc _ = *v8ptr //@ ssa(v8ptr,"Alloc")
v8a := make([]int, 1) // v8a::Slice v8a := make([]int, 1) //@ ssa(v8a,"Slice")
v8a[0] = 0 // v8a::Slice v8a[0] = 0 //@ ssa(v8a,"Slice")
print(v8a[:]) // v8a::Slice print(v8a[:]) //@ ssa(v8a,"Slice")
v9 := S{} // &v9::Alloc v9 := S{} //@ ssa(v9,"&Alloc")
v10 := &v9 // v10::Alloc &v9::Alloc v10 := &v9 //@ ssa(v10,"Alloc"), ssa(v9,"&Alloc")
_ = v10 // v10::Alloc _ = v10 //@ ssa(v10,"Alloc")
var v11 *J = nil // v11::Const var v11 *J = nil //@ ssa(v11,"Const")
v11.method() // v11::Const v11.method() //@ ssa(v11,"Const")
var v12 J // &v12::Alloc var v12 J //@ ssa(v12,"&Alloc")
v12.method() // &v12::Alloc (implicitly address-taken) v12.method() //@ ssa(v12,"&Alloc") // implicitly address-taken
// NB, in the following, 'method' resolves to the *types.Func // NB, in the following, 'method' resolves to the *types.Func
// of (*J).method, so it doesn't help us locate the specific // of (*J).method, so it doesn't help us locate the specific
// ssa.Values here: a bound-method closure and a promotion // ssa.Values here: a bound-method closure and a promotion
// wrapper. // wrapper.
_ = v11.method // v11::Const _ = v11.method //@ ssa(v11,"Const")
_ = (*struct{ J }).method // J::nil _ = (*struct{ J }).method //@ ssa(J,"nil")
// These vars are not optimised away. // These vars are not optimised away.
if false { if false {
v13 := 0 // v13::Const v13 := 0 //@ ssa(v13,"Const")
println(v13) // v13::Const println(v13) //@ ssa(v13,"Const")
} }
switch x := 1; x { // x::Const switch x := 1; x { //@ ssa(x,"Const")
case v0: // v0::Phi case v0: //@ ssa(v0,"Phi")
} }
for k, v := range m { // k::Extract v::Extract m::MakeMap for k, v := range m { //@ ssa(k,"Extract"), ssa(v,"Extract"), ssa(m,"MakeMap")
_ = k // k::Extract _ = k //@ ssa(k,"Extract")
v++ // v::BinOp 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) var i interface{} //@ ssa(i,"Const") // nil interface
i = 1 // i::MakeInterface i = 1 //@ ssa(i,"MakeInterface")
switch i := i.(type) { // i::MakeInterface i::MakeInterface switch i := i.(type) { //@ ssa(i,"MakeInterface"), ssa(i,"MakeInterface")
case int: 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 { select {
case x := <-ch: // x::UnOp (receive) ch::MakeChan case x := <-ch: //@ ssa(x,"UnOp") /*receive*/, ssa(ch,"MakeChan")
_ = x // x::UnOp _ = x //@ ssa(x,"UnOp")
} }
// .Op is an inter-package FieldVal-selection. // .Op is an inter-package FieldVal-selection.
var err os.PathError // &err::Alloc var err os.PathError //@ ssa(err,"&Alloc")
_ = err.Op // &err::Alloc &Op::FieldAddr _ = err.Op //@ ssa(err,"&Alloc"), ssa(Op,"&FieldAddr")
_ = &err.Op // &err::Alloc &Op::FieldAddr _ = &err.Op //@ ssa(err,"&Alloc"), ssa(Op,"&FieldAddr")
// Exercise corner-cases of lvalues vs rvalues. // Exercise corner-cases of lvalues vs rvalues.
// (Guessing IsAddr from the 'pointerness' won't cut it here.) // (Guessing IsAddr from the 'pointerness' won't cut it here.)
type N *N type N *N
var n N // n::Const var n N //@ ssa(n,"Const")
n1 := n // n1::Const n::Const n1 := n //@ ssa(n1,"Const"), ssa(n,"Const")
n2 := &n1 // n2::Alloc &n1::Alloc n2 := &n1 //@ ssa(n2,"Alloc"), ssa(n1,"&Alloc")
n3 := *n2 // n3::UnOp n2::Alloc n3 := *n2 //@ ssa(n3,"UnOp"), ssa(n2,"Alloc")
n4 := **n3 // n4::UnOp n3::UnOp n4 := **n3 //@ ssa(n4,"UnOp"), ssa(n3,"UnOp")
_ = n4 // n4::UnOp _ = n4 //@ ssa(n4,"UnOp")
} }