2
2
// Use of this source code is governed by a BSD-style
3
3
// license that can be found in the LICENSE file.
4
4
5
+ //go:debug gotypesalias=1
6
+
5
7
package facts_test
6
8
7
9
import (
@@ -18,8 +20,10 @@ import (
18
20
19
21
"golang.org/x/tools/go/analysis/analysistest"
20
22
"golang.org/x/tools/go/packages"
23
+ "golang.org/x/tools/internal/aliases"
21
24
"golang.org/x/tools/internal/facts"
22
25
"golang.org/x/tools/internal/testenv"
26
+ "golang.org/x/tools/internal/typesinternal"
23
27
)
24
28
25
29
type myFact struct {
@@ -35,10 +39,9 @@ func init() {
35
39
36
40
func TestEncodeDecode (t * testing.T ) {
37
41
tests := []struct {
38
- name string
39
- typeparams bool // requires typeparams to be enabled
40
- files map [string ]string
41
- plookups []pkgLookups // see testEncodeDecode for details
42
+ name string
43
+ files map [string ]string
44
+ plookups []pkgLookups // see testEncodeDecode for details
42
45
}{
43
46
{
44
47
name : "loading-order" ,
@@ -184,8 +187,7 @@ func TestEncodeDecode(t *testing.T) {
184
187
},
185
188
},
186
189
{
187
- name : "typeparams" ,
188
- typeparams : true ,
190
+ name : "typeparams" ,
189
191
files : map [string ]string {
190
192
"a/a.go" : `package a
191
193
type T1 int
@@ -202,9 +204,9 @@ func TestEncodeDecode(t *testing.T) {
202
204
type N3[T a.T3] func() T
203
205
type N4[T a.T4|int8] func() T
204
206
type N5[T interface{Bar() a.T5} ] func() T
205
-
207
+
206
208
type t5 struct{}; func (t5) Bar() a.T5 { return 0 }
207
-
209
+
208
210
var G1 N1[a.T1]
209
211
var G2 func() N2[a.T2]
210
212
var G3 N3[a.T3]
@@ -222,7 +224,7 @@ func TestEncodeDecode(t *testing.T) {
222
224
v5 = b.G5
223
225
v6 = b.F6[t6]
224
226
)
225
-
227
+
226
228
type t6 struct{}; func (t6) Foo() {}
227
229
` ,
228
230
},
@@ -244,19 +246,44 @@ func TestEncodeDecode(t *testing.T) {
244
246
},
245
247
},
246
248
}
247
-
248
- for i := range tests {
249
- test := tests [i ]
249
+ for _ , test := range tests {
250
250
t .Run (test .name , func (t * testing.T ) {
251
251
t .Parallel ()
252
252
testEncodeDecode (t , test .files , test .plookups )
253
253
})
254
254
}
255
255
}
256
256
257
+ func TestEncodeDecodeAliases (t * testing.T ) {
258
+ testenv .NeedsGo1Point (t , 24 )
259
+
260
+ files := map [string ]string {
261
+ "a/a.go" : `package a
262
+ type A = int
263
+ ` ,
264
+ "b/b.go" : `package b
265
+ import "a"
266
+ type B = a.A
267
+ ` ,
268
+ "c/c.go" : `package c
269
+ import "b";
270
+ type N1[T int|~string] = struct{}
271
+
272
+ var V1 = N1[b.B]{}
273
+ ` ,
274
+ }
275
+ plookups := []pkgLookups {
276
+ {"a" , []lookup {}},
277
+ {"b" , []lookup {}},
278
+ // fake objexpr for RHS of V1's type arg (see customFind hack)
279
+ {"c" , []lookup {{"c.V1->c.N1->b.B->a.A" , "myFact(a.A)" }}},
280
+ }
281
+ testEncodeDecode (t , files , plookups )
282
+ }
283
+
257
284
type lookup struct {
258
- objexpr string
259
- want string
285
+ objexpr string // expression whose type is a named type
286
+ want string // printed form of fact associated with that type (or "no fact")
260
287
}
261
288
262
289
type pkgLookups struct {
@@ -345,22 +372,37 @@ func testEncodeDecode(t *testing.T, files map[string]string, tests []pkgLookups)
345
372
}
346
373
}
347
374
375
+ // customFind allows for overriding how an object is looked up
376
+ // by find. This is necessary for objects that are accessible through
377
+ // the API but are not the type of any expression we can pass to types.CheckExpr.
378
+ var customFind = map [string ]func (p * types.Package ) types.Object {
379
+ "c.V1->c.N1->b.B->a.A" : func (p * types.Package ) types.Object {
380
+ cV1 := p .Scope ().Lookup ("V1" )
381
+ cN1 := cV1 .Type ().(* types.Alias )
382
+ aT1 := aliases .TypeArgs (cN1 ).At (0 ).(* types.Alias )
383
+ zZ1 := aliases .Rhs (aT1 ).(* types.Alias )
384
+ return zZ1 .Obj ()
385
+ },
386
+ }
387
+
348
388
func find (p * types.Package , expr string ) types.Object {
349
389
// types.Eval only allows us to compute a TypeName object for an expression.
350
390
// TODO(adonovan): support other expressions that denote an object:
351
391
// - an identifier (or qualified ident) for a func, const, or var
352
392
// - new(T).f for a field or method
353
393
// I've added CheckExpr in https://go-review.googlesource.com/c/go/+/144677.
354
394
// If that becomes available, use it.
355
-
395
+ if f := customFind [expr ]; f != nil {
396
+ return f (p )
397
+ }
356
398
// Choose an arbitrary position within the (single-file) package
357
399
// so that we are within the scope of its import declarations.
358
400
somepos := p .Scope ().Lookup (p .Scope ().Names ()[0 ]).Pos ()
359
401
tv , err := types .Eval (token .NewFileSet (), p , somepos , expr )
360
402
if err != nil {
361
403
return nil
362
404
}
363
- if n , ok := types . Unalias ( tv .Type ).( * types. Named ); ok {
405
+ if n , ok := tv .Type .(typesinternal. NamedOrAlias ); ok {
364
406
return n .Obj ()
365
407
}
366
408
return nil
0 commit comments