diff --git a/x/typesutil/info_test.go b/x/typesutil/info_test.go index b083ff9be..bd1d4584b 100644 --- a/x/typesutil/info_test.go +++ b/x/typesutil/info_test.go @@ -112,7 +112,7 @@ func parseSource(fset *token.FileSet, filename string, src interface{}, mode par return nil, nil, err } - pkg := types.NewPackage("main", f.Name.Name) + pkg := types.NewPackage("", f.Name.Name) conf := &types.Config{} conf.Importer = importer.Default() chkOpts := &typesutil.Config{ @@ -150,7 +150,7 @@ func parseGoSource(fset *token.FileSet, filename string, src interface{}, mode g Selections: make(map[*goast.SelectorExpr]*types.Selection), Scopes: make(map[goast.Node]*types.Scope), } - pkg := types.NewPackage("main", f.Name.Name) + pkg := types.NewPackage("", f.Name.Name) check := types.NewChecker(conf, fset, pkg, info) err = check.Files([]*goast.File{f}) return pkg, info, err @@ -1671,3 +1671,132 @@ func onCloned() { 009: 15: 9 | info | type main.info struct{x int; y int} 010: 19: 2 | say | func (*github.com/goplus/gop/cl/internal/spx.Sprite).Say(msg string, secs ...float64)`) } + +func TestScopesInfo(t *testing.T) { + var tests = []struct { + src string + scopes []string // list of scope descriptors of the form kind:varlist + }{ + {`package p0`, []string{ + "file:", + }}, + {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{ + "file:fmt m", + }}, + {`package p2; func _() {}`, []string{ + "file:", "func:", + }}, + {`package p3; func _(x, y int) {}`, []string{ + "file:", "func:x y", + }}, + {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{ + "file:", "func:x y z", // redeclaration of x + }}, + {`package p5; func _(x, y int) (u, _ int) { return }`, []string{ + "file:", "func:u x y", + }}, + {`package p6; func _() { { var x int; _ = x } }`, []string{ + "file:", "func:", "block:x", + }}, + {`package p7; func _() { if true {} }`, []string{ + "file:", "func:", "if:", "block:", + }}, + {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{ + "file:", "func:", "if:x", "block:y", + }}, + {`package p9; func _() { switch x := 0; x {} }`, []string{ + "file:", "func:", "switch:x", + }}, + {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{ + "file:", "func:", "switch:x", "case:y", "case:", + }}, + {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{ + "file:", "func:t", "type switch:", + }}, + {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{ + "file:", "func:t", "type switch:t", + }}, + {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{ + "file:", "func:t", "type switch:", "case:x", // x implicitly declared + }}, + {`package p14; func _() { select{} }`, []string{ + "file:", "func:", + }}, + {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{ + "file:", "func:c", "comm:", + }}, + {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{ + "file:", "func:c", "comm:i x", + }}, + {`package p17; func _() { for{} }`, []string{ + "file:", "func:", "for:", "block:", + }}, + {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{ + "file:", "func:n", "for:i", "block:", + }}, + {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{ + "file:", "func:a", "range:i", "block:", + }}, + {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{ + "file:", "func:a", "range:i x", "block:", + }}, + {`package p21; var s int; func _(a []int) { for i, x := range a { c := i; println(c) } }`, []string{ + "file:", "func:a", "range:i x", "block:c", + }}, + } + + for _, test := range tests { + pkg, info, err := parseSource(token.NewFileSet(), "src.gop", test.src, 0) + if err != nil { + t.Fatalf("parse source failed: %v", test.src) + } + name := pkg.Name() + // number of scopes must match + if len(info.Scopes) != len(test.scopes) { + t.Errorf("package %s: got %d scopes; want %d\n%v\n%v", name, len(info.Scopes), len(test.scopes), + test.scopes, info.Scopes) + } + + // scope descriptions must match + for node, scope := range info.Scopes { + kind := "" + switch node.(type) { + case *ast.File: + kind = "file" + case *ast.FuncType: + kind = "func" + case *ast.BlockStmt: + kind = "block" + case *ast.IfStmt: + kind = "if" + case *ast.SwitchStmt: + kind = "switch" + case *ast.TypeSwitchStmt: + kind = "type switch" + case *ast.CaseClause: + kind = "case" + case *ast.CommClause: + kind = "comm" + case *ast.ForStmt: + kind = "for" + case *ast.RangeStmt: + kind = "range" + default: + kind = fmt.Sprintf(" %T", node) + } + + // look for matching scope description + desc := kind + ":" + strings.Join(scope.Names(), " ") + found := false + for _, d := range test.scopes { + if desc == d { + found = true + break + } + } + if !found { + t.Errorf("package %s: no matching scope found for %s", name, desc) + } + } + } +}