@@ -115,3 +115,58 @@ func TestUnder(t *testing.T) {
115115 })
116116 }
117117}
118+
119+ func TestField (t * testing.T ) {
120+ t .Parallel ()
121+
122+ lookup := func (pass * analysis.Pass , n string ) (types.Type , error ) {
123+ _ , obj := pass .Pkg .Scope ().LookupParent (n , token .NoPos )
124+ if obj == nil {
125+ return nil , fmt .Errorf ("does not find: %s" , n )
126+ }
127+ return obj .Type (), nil
128+ }
129+
130+ cases := map [string ]struct {
131+ src string
132+ typ string
133+ field string
134+ want int
135+ }{
136+ "nomarl" : {"type a struct{n int}" , "a" , "n" , 0 },
137+ "nofield" : {"type a struct{n int}" , "a" , "m" , - 1 },
138+ "empty" : {"type a struct{}" , "a" , "n" , - 1 },
139+ "two" : {"type a struct{n, m int}" , "a" , "m" , 1 },
140+ "nonamed" : {"var a struct{n, m int}" , "a" , "m" , 1 },
141+ "ptr" : {"var a *struct{n, m int}" , "a" , "m" , 1 },
142+ "namednamed" : {"type a struct{n int}; type b a" , "b" , "n" , 0 },
143+ "alias" : {"type a struct{n int}; type b = a" , "b" , "n" , 0 },
144+ }
145+
146+ for name , tt := range cases {
147+ name , tt := name , tt
148+ t .Run (name , func (t * testing.T ) {
149+ t .Parallel ()
150+ a := & analysis.Analyzer {
151+ Name : name + "Analyzer" ,
152+ Run : func (pass * analysis.Pass ) (interface {}, error ) {
153+ typ , err := lookup (pass , tt .typ )
154+ if err != nil {
155+ return nil , err
156+ }
157+
158+ got , _ := analysisutil .Field (typ , tt .field )
159+ if tt .want != got {
160+ return nil , fmt .Errorf ("want %v but got %v" , tt .want , got )
161+ }
162+ return nil , nil
163+ },
164+ }
165+ path := filepath .Join (name , name + ".go" )
166+ dir := WriteFiles (t , map [string ]string {
167+ path : fmt .Sprintf ("package %s\n %s" , name , tt .src ),
168+ })
169+ analysistest .Run (t , dir , a , name )
170+ })
171+ }
172+ }
0 commit comments