Source file
src/go/types/scope2_test.go
1
2
3
4
5 package types_test
6
7 import (
8 "fmt"
9 "go/ast"
10 "go/token"
11 "reflect"
12 "regexp"
13 "strings"
14 "testing"
15
16 . "go/types"
17 )
18
19
20
21 func TestScopeLookupParent(t *testing.T) {
22 fset := token.NewFileSet()
23 imports := make(testImporter)
24 conf := Config{Importer: imports}
25 var info Info
26 makePkg := func(path string, files ...*ast.File) {
27 var err error
28 imports[path], err = conf.Check(path, fset, files, &info)
29 if err != nil {
30 t.Fatal(err)
31 }
32 }
33
34 makePkg("lib", mustParse(fset, "package lib; var X int"))
35
36
37
38
39
40
41 mainSrc := `
42 /*lib=pkgname:5*/ /*X=var:1*/ /*Pi=const:8*/ /*T=typename:9*/ /*Y=var:10*/ /*F=func:12*/
43 package main
44
45 import "lib"
46 import . "lib"
47
48 const Pi = 3.1415
49 type T struct{}
50 var Y, _ = lib.X, X
51
52 func F[T *U, U any](param1, param2 int) /*param1=undef*/ (res1 /*res1=undef*/, res2 int) /*param1=var:12*/ /*res1=var:12*/ /*U=typename:12*/ {
53 const pi, e = 3.1415, /*pi=undef*/ 2.71828 /*pi=const:13*/ /*e=const:13*/
54 type /*t=undef*/ t /*t=typename:14*/ *t
55 print(Y) /*Y=var:10*/
56 x, Y := Y, /*x=undef*/ /*Y=var:10*/ Pi /*x=var:16*/ /*Y=var:16*/ ; _ = x; _ = Y
57 var F = /*F=func:12*/ F[*int, int] /*F=var:17*/ ; _ = F
58
59 var a []int
60 for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
61
62 var i interface{}
63 switch y := i.(type) { /*y=undef*/
64 case /*y=undef*/ int /*y=undef*/ : /*y=var:23*/ ;
65 case float32, /*y=undef*/ float64 /*y=undef*/ : /*y=var:23*/ ;
66 default /*y=undef*/ : /*y=var:23*/
67 println(y)
68 }
69 /*y=undef*/
70
71 switch int := i.(type) {
72 case /*int=typename:0*/ int /*int=typename:0*/ : /*int=var:31*/
73 println(int)
74 default /*int=typename:0*/ : /*int=var:31*/ ;
75 }
76
77 _ = param1
78 _ = res1
79 return
80 }
81 /*main=undef*/
82 `
83
84 info.Uses = make(map[*ast.Ident]Object)
85 f := mustParse(fset, mainSrc)
86 makePkg("main", f)
87 mainScope := imports["main"].Scope()
88 rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`)
89 for _, group := range f.Comments {
90 for _, comment := range group.List {
91
92 m := rx.FindStringSubmatch(comment.Text)
93 if m == nil {
94 t.Errorf("%s: bad comment: %s",
95 fset.Position(comment.Pos()), comment.Text)
96 continue
97 }
98 name, want := m[1], m[2]
99
100
101 inner := mainScope.Innermost(comment.Pos())
102 if inner == nil {
103 t.Errorf("%s: at %s: can't find innermost scope",
104 fset.Position(comment.Pos()), comment.Text)
105 continue
106 }
107 got := "undef"
108 if _, obj := inner.LookupParent(name, comment.Pos()); obj != nil {
109 kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
110 got = fmt.Sprintf("%s:%d", kind, fset.Position(obj.Pos()).Line)
111 }
112 if got != want {
113 t.Errorf("%s: at %s: %s resolved to %s, want %s",
114 fset.Position(comment.Pos()), comment.Text, name, got, want)
115 }
116 }
117 }
118
119
120
121
122
123 for id, wantObj := range info.Uses {
124 inner := mainScope.Innermost(id.Pos())
125 if inner == nil {
126 t.Errorf("%s: can't find innermost scope enclosing %q",
127 fset.Position(id.Pos()), id.Name)
128 continue
129 }
130
131
132
133
134
135 if id.Name == "X" {
136 continue
137 }
138
139 _, gotObj := inner.LookupParent(id.Name, id.Pos())
140 if gotObj != wantObj {
141
142 var printScopeTree func(indent string, s *Scope)
143 printScopeTree = func(indent string, s *Scope) {
144 t.Logf("%sscope %s %v-%v = %v",
145 indent,
146 ScopeComment(s),
147 s.Pos(),
148 s.End(),
149 s.Names())
150 for i := range s.NumChildren() {
151 printScopeTree(indent+" ", s.Child(i))
152 }
153 }
154 printScopeTree("", mainScope)
155
156 t.Errorf("%s: Scope(%s).LookupParent(%s@%v) got %v, want %v [scopePos=%v]",
157 fset.Position(id.Pos()),
158 ScopeComment(inner),
159 id.Name,
160 id.Pos(),
161 gotObj,
162 wantObj,
163 ObjectScopePos(wantObj))
164 continue
165 }
166 }
167 }
168
View as plain text