1
2
3
4
5
6
7
8 package gcimporter
9
10 import (
11 "bytes"
12 "fmt"
13 "go/ast"
14 "go/constant"
15 goimporter "go/importer"
16 goparser "go/parser"
17 "go/token"
18 "go/types"
19 "os"
20 "os/exec"
21 "path"
22 "path/filepath"
23 "runtime"
24 "sort"
25 "strings"
26 "sync"
27 "testing"
28 "time"
29
30 "golang.org/x/tools/internal/aliases"
31 "golang.org/x/tools/internal/goroot"
32 "golang.org/x/tools/internal/testenv"
33 )
34
35 func TestMain(m *testing.M) {
36 testenv.ExitIfSmallMachine()
37 os.Exit(m.Run())
38 }
39
40
41
42 func needsCompiler(t *testing.T, compiler string) {
43 if runtime.Compiler == compiler {
44 return
45 }
46 switch compiler {
47 case "gc":
48 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
49 }
50 }
51
52
53
54
55 func compile(t *testing.T, dirname, filename, outdirname string, packagefiles map[string]string) string {
56 return compilePkg(t, dirname, filename, outdirname, packagefiles, "p")
57 }
58
59 func compilePkg(t *testing.T, dirname, filename, outdirname string, packagefiles map[string]string, pkg string) string {
60 testenv.NeedsGoBuild(t)
61
62
63 basename := strings.TrimSuffix(filepath.Base(filename), ".go")
64 ok := filename != basename
65 if !ok {
66 t.Fatalf("filename doesn't end in .go: %s", filename)
67 }
68 objname := basename + ".o"
69 outname := filepath.Join(outdirname, objname)
70
71 importcfgfile := os.DevNull
72 if len(packagefiles) > 0 {
73 importcfgfile = filepath.Join(outdirname, basename) + ".importcfg"
74 importcfg := new(bytes.Buffer)
75 fmt.Fprintf(importcfg, "# import config")
76 for k, v := range packagefiles {
77 fmt.Fprintf(importcfg, "\npackagefile %s=%s\n", k, v)
78 }
79 if err := os.WriteFile(importcfgfile, importcfg.Bytes(), 0655); err != nil {
80 t.Fatal(err)
81 }
82 }
83
84 importreldir := strings.ReplaceAll(outdirname, string(os.PathSeparator), "/")
85 cmd := exec.Command("go", "tool", "compile", "-p", pkg, "-D", importreldir, "-importcfg", importcfgfile, "-o", outname, filename)
86 cmd.Dir = dirname
87 if out, err := cmd.CombinedOutput(); err != nil {
88 t.Logf("%s", out)
89 t.Fatalf("go tool compile %s failed: %s", filename, err)
90 }
91 return outname
92 }
93
94 func testPath(t *testing.T, path, srcDir string) *types.Package {
95 t0 := time.Now()
96 pkg, err := Import(make(map[string]*types.Package), path, srcDir, nil)
97 if err != nil {
98 t.Errorf("testPath(%s): %s", path, err)
99 return nil
100 }
101 t.Logf("testPath(%s): %v", path, time.Since(t0))
102 return pkg
103 }
104
105 func mktmpdir(t *testing.T) string {
106 tmpdir, err := os.MkdirTemp("", "gcimporter_test")
107 if err != nil {
108 t.Fatal("mktmpdir:", err)
109 }
110 if err := os.Mkdir(filepath.Join(tmpdir, "testdata"), 0700); err != nil {
111 os.RemoveAll(tmpdir)
112 t.Fatal("mktmpdir:", err)
113 }
114 return tmpdir
115 }
116
117 const testfile = "exports.go"
118
119 func TestImportTestdata(t *testing.T) {
120 needsCompiler(t, "gc")
121 testenv.NeedsGoBuild(t)
122
123 tmpdir := mktmpdir(t)
124 defer os.RemoveAll(tmpdir)
125
126 packageFiles := map[string]string{}
127 for _, pkg := range []string{"go/ast", "go/token"} {
128 export, _ := FindPkg(pkg, "testdata")
129 if export == "" {
130 t.Fatalf("no export data found for %s", pkg)
131 }
132 packageFiles[pkg] = export
133 }
134
135 compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"), packageFiles)
136
137
138 filename := testfile[:len(testfile)-3]
139 if pkg := testPath(t, "./testdata/"+filename, tmpdir); pkg != nil {
140
141
142
143
144
145
146
147
148
149 got := fmt.Sprint(pkg.Imports())
150 wants := []string{"go/ast", "go/token"}
151 if unifiedIR {
152 wants = []string{"go/ast"}
153 }
154 for _, want := range wants {
155 if !strings.Contains(got, want) {
156 t.Errorf(`Package("exports").Imports() = %s, does not contain %s`, got, want)
157 }
158 }
159 }
160 }
161
162 func TestImportTypeparamTests(t *testing.T) {
163 if testing.Short() {
164 t.Skipf("in short mode, skipping test that requires export data for all of std")
165 }
166
167 testenv.NeedsGoBuild(t)
168
169
170 if runtime.Compiler != "gc" {
171 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
172 }
173
174 tmpdir := mktmpdir(t)
175 defer os.RemoveAll(tmpdir)
176
177
178
179 rootDir := filepath.Join(runtime.GOROOT(), "test", "typeparam")
180 list, err := os.ReadDir(rootDir)
181 if err != nil {
182 t.Fatal(err)
183 }
184
185 var skip map[string]string
186 if !unifiedIR {
187
188 skip = map[string]string{
189 "equal.go": "inconsistent embedded sorting",
190 "nested.go": "fails to compile",
191 "issue47631.go": "can not handle local type declarations",
192 "issue55101.go": "fails to compile",
193 }
194 }
195
196 for _, entry := range list {
197 if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
198
199 continue
200 }
201
202 t.Run(entry.Name(), func(t *testing.T) {
203 if reason, ok := skip[entry.Name()]; ok {
204 t.Skip(reason)
205 }
206
207 filename := filepath.Join(rootDir, entry.Name())
208 src, err := os.ReadFile(filename)
209 if err != nil {
210 t.Fatal(err)
211 }
212 if !bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// compile")) {
213
214
215
216 t.Skipf("not detected as a run test")
217 }
218
219
220
221 pkgFiles, err := goroot.PkgfileMap()
222 if err != nil {
223 t.Fatal(err)
224 }
225 compile(t, rootDir, entry.Name(), filepath.Join(tmpdir, "testdata"), pkgFiles)
226 pkgName := strings.TrimSuffix(entry.Name(), ".go")
227 imported := importPkg(t, "./testdata/"+pkgName, tmpdir)
228 checked := checkFile(t, filename, src)
229
230 seen := make(map[string]bool)
231 for _, name := range imported.Scope().Names() {
232 if !token.IsExported(name) {
233 continue
234 }
235 seen[name] = true
236
237 importedObj := imported.Scope().Lookup(name)
238 got := types.ObjectString(importedObj, types.RelativeTo(imported))
239
240 checkedObj := checked.Scope().Lookup(name)
241 if checkedObj == nil {
242 t.Fatalf("imported object %q was not type-checked", name)
243 }
244 want := types.ObjectString(checkedObj, types.RelativeTo(checked))
245
246 if got != want {
247 t.Errorf("imported %q as %q, want %q", name, got, want)
248 }
249 }
250
251 for _, name := range checked.Scope().Names() {
252 if !token.IsExported(name) || seen[name] {
253 continue
254 }
255 t.Errorf("did not import object %q", name)
256 }
257 })
258 }
259 }
260
261 func checkFile(t *testing.T, filename string, src []byte) *types.Package {
262 fset := token.NewFileSet()
263 f, err := goparser.ParseFile(fset, filename, src, 0)
264 if err != nil {
265 t.Fatal(err)
266 }
267 config := types.Config{
268 Importer: goimporter.Default(),
269 }
270 pkg, err := config.Check("", fset, []*ast.File{f}, nil)
271 if err != nil {
272 t.Fatal(err)
273 }
274 return pkg
275 }
276
277 func TestVersionHandling(t *testing.T) {
278 if debug {
279 t.Skip("TestVersionHandling panics in debug mode")
280 }
281
282
283 needsCompiler(t, "gc")
284
285 const dir = "./testdata/versions"
286 list, err := os.ReadDir(dir)
287 if err != nil {
288 t.Fatal(err)
289 }
290
291 tmpdir := mktmpdir(t)
292 defer os.RemoveAll(tmpdir)
293 corruptdir := filepath.Join(tmpdir, "testdata", "versions")
294 if err := os.Mkdir(corruptdir, 0700); err != nil {
295 t.Fatal(err)
296 }
297
298 for _, f := range list {
299 name := f.Name()
300 if !strings.HasSuffix(name, ".a") {
301 continue
302 }
303 if strings.Contains(name, "corrupted") {
304 continue
305 }
306 pkgpath := "./" + name[:len(name)-2]
307
308 if testing.Verbose() {
309 t.Logf("importing %s", name)
310 }
311
312
313 _, err := Import(make(map[string]*types.Package), pkgpath, dir, nil)
314 if err != nil {
315 t.Errorf("import %q failed: %v", pkgpath, err)
316 continue
317 }
318
319
320
321 data, err := os.ReadFile(filepath.Join(dir, name))
322 if err != nil {
323 t.Fatal(err)
324 }
325
326 i := bytes.Index(data, []byte("\n$$B\n")) + 5
327 j := bytes.Index(data[i:], []byte("\n$$\n")) + i
328 if i < 0 || j < 0 || i > j {
329 t.Fatalf("export data section not found (i = %d, j = %d)", i, j)
330 }
331
332 for k := j - 13; k >= i; k -= 7 {
333 data[k]++
334 }
335
336 pkgpath += "_corrupted"
337 filename := filepath.Join(corruptdir, pkgpath) + ".a"
338 os.WriteFile(filename, data, 0666)
339
340
341 _, err = Import(make(map[string]*types.Package), pkgpath, corruptdir, nil)
342 if err == nil {
343 t.Errorf("import corrupted %q succeeded", pkgpath)
344 } else if msg := err.Error(); !strings.Contains(msg, "internal error") {
345 t.Errorf("import %q error incorrect (%s)", pkgpath, msg)
346 }
347 }
348 }
349
350 func TestImportStdLib(t *testing.T) {
351 if testing.Short() {
352 t.Skip("the imports can be expensive, and this test is especially slow when the build cache is empty")
353 }
354
355 needsCompiler(t, "gc")
356 testenv.NeedsGoBuild(t)
357
358
359 var stderr bytes.Buffer
360 cmd := exec.Command("go", "list", "-f", "{{if .GoFiles}}{{.ImportPath}}{{end}}", "std")
361 cmd.Stderr = &stderr
362 out, err := cmd.Output()
363 if err != nil {
364 t.Fatalf("failed to run go list to determine stdlib packages: %v\nstderr:\n%v", err, stderr.String())
365 }
366 pkgs := strings.Fields(string(out))
367
368 var nimports int
369 for _, pkg := range pkgs {
370 t.Run(pkg, func(t *testing.T) {
371 if testPath(t, pkg, filepath.Join(testenv.GOROOT(t), "src", path.Dir(pkg))) != nil {
372 nimports++
373 }
374 })
375 }
376 const minPkgs = 225
377 if len(pkgs) < minPkgs {
378 t.Fatalf("too few packages (%d) were imported", nimports)
379 }
380
381 t.Logf("tested %d imports", nimports)
382 }
383
384 var importedObjectTests = []struct {
385 name string
386 want string
387 }{
388
389 {"crypto.Hash", "type Hash uint"},
390 {"go/ast.ObjKind", "type ObjKind int"},
391 {"go/types.Qualifier", "type Qualifier func(*Package) string"},
392 {"go/types.Comparable", "func Comparable(T Type) bool"},
393 {"math.Pi", "const Pi untyped float"},
394 {"math.Sin", "func Sin(x float64) float64"},
395 {"go/ast.NotNilFilter", "func NotNilFilter(_ string, v reflect.Value) bool"},
396
397
398 {"context.Context", "type Context interface{Deadline() (deadline time.Time, ok bool); Done() <-chan struct{}; Err() error; Value(key any) any}"},
399 {"crypto.Decrypter", "type Decrypter interface{Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error); Public() PublicKey}"},
400 {"encoding.BinaryMarshaler", "type BinaryMarshaler interface{MarshalBinary() (data []byte, err error)}"},
401 {"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
402 {"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
403 {"go/ast.Node", "type Node interface{End() go/token.Pos; Pos() go/token.Pos}"},
404 {"go/types.Type", "type Type interface{String() string; Underlying() Type}"},
405 }
406
407 func TestImportedTypes(t *testing.T) {
408
409 needsCompiler(t, "gc")
410 testenv.NeedsGoBuild(t)
411
412 for _, test := range importedObjectTests {
413 obj := importObject(t, test.name)
414 if obj == nil {
415 continue
416 }
417 got := types.ObjectString(obj, types.RelativeTo(obj.Pkg()))
418
419
420 if got != test.want && test.want == strings.ReplaceAll(got, "interface{}", "any") {
421 got = test.want
422 }
423
424 if got != test.want {
425 t.Errorf("%s: got %q; want %q", test.name, got, test.want)
426 }
427
428 if named, _ := aliases.Unalias(obj.Type()).(*types.Named); named != nil {
429 verifyInterfaceMethodRecvs(t, named, 0)
430 }
431 }
432 }
433
434 func TestImportedConsts(t *testing.T) {
435 testenv.NeedsGoBuild(t)
436
437 tests := []struct {
438 name string
439 want constant.Kind
440 }{
441 {"math.Pi", constant.Float},
442 {"math.MaxFloat64", constant.Float},
443 {"math.MaxInt64", constant.Int},
444 }
445
446 for _, test := range tests {
447 obj := importObject(t, test.name)
448 if got := obj.(*types.Const).Val().Kind(); got != test.want {
449 t.Errorf("%s: imported as constant.Kind(%v), want constant.Kind(%v)", test.name, got, test.want)
450 }
451 }
452 }
453
454
455
456
457
458
459 func importObject(t *testing.T, name string) types.Object {
460 s := strings.Split(name, ".")
461 if len(s) != 2 {
462 t.Fatal("inconsistent test data")
463 }
464 importPath := s[0]
465 objName := s[1]
466
467 pkg, err := Import(make(map[string]*types.Package), importPath, ".", nil)
468 if err != nil {
469 t.Error(err)
470 return nil
471 }
472
473 obj := pkg.Scope().Lookup(objName)
474 if obj == nil {
475 t.Errorf("%s: object not found", name)
476 return nil
477 }
478 return obj
479 }
480
481
482
483 func verifyInterfaceMethodRecvs(t *testing.T, named *types.Named, level int) {
484
485 if level > 10 {
486 t.Errorf("%s: embeds itself", named)
487 return
488 }
489
490 iface, _ := named.Underlying().(*types.Interface)
491 if iface == nil {
492 return
493 }
494
495
496 for i := 0; i < iface.NumExplicitMethods(); i++ {
497 m := iface.ExplicitMethod(i)
498 recv := m.Type().(*types.Signature).Recv()
499 if recv == nil {
500 t.Errorf("%s: missing receiver type", m)
501 continue
502 }
503 if recv.Type() != named {
504 t.Errorf("%s: got recv type %s; want %s", m, recv.Type(), named)
505 }
506 }
507
508
509 for i := 0; i < iface.NumEmbeddeds(); i++ {
510
511 if etype, _ := aliases.Unalias(iface.EmbeddedType(i)).(*types.Named); etype != nil {
512 verifyInterfaceMethodRecvs(t, etype, level+1)
513 }
514 }
515 }
516
517 func TestIssue5815(t *testing.T) {
518
519 needsCompiler(t, "gc")
520 testenv.NeedsGoBuild(t)
521
522 pkg := importPkg(t, "strings", ".")
523
524 scope := pkg.Scope()
525 for _, name := range scope.Names() {
526 obj := scope.Lookup(name)
527 if obj.Pkg() == nil {
528 t.Errorf("no pkg for %s", obj)
529 }
530 if tname, _ := obj.(*types.TypeName); tname != nil {
531 named := aliases.Unalias(tname.Type()).(*types.Named)
532 for i := 0; i < named.NumMethods(); i++ {
533 m := named.Method(i)
534 if m.Pkg() == nil {
535 t.Errorf("no pkg for %s", m)
536 }
537 }
538 }
539 }
540 }
541
542
543 func TestCorrectMethodPackage(t *testing.T) {
544
545 needsCompiler(t, "gc")
546 testenv.NeedsGoBuild(t)
547
548 imports := make(map[string]*types.Package)
549 _, err := Import(imports, "net/http", ".", nil)
550 if err != nil {
551 t.Fatal(err)
552 }
553
554 mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
555 mset := types.NewMethodSet(types.NewPointer(mutex))
556 sel := mset.Lookup(nil, "Lock")
557 lock := sel.Obj().(*types.Func)
558 if got, want := lock.Pkg().Path(), "sync"; got != want {
559 t.Errorf("got package path %q; want %q", got, want)
560 }
561 }
562
563 func TestIssue13566(t *testing.T) {
564
565 needsCompiler(t, "gc")
566 testenv.NeedsGoBuild(t)
567
568
569
570 if runtime.GOOS == "windows" {
571 t.Skip("avoid dealing with relative paths/drive letters on windows")
572 }
573
574 tmpdir := mktmpdir(t)
575 defer os.RemoveAll(tmpdir)
576 testoutdir := filepath.Join(tmpdir, "testdata")
577
578
579
580
581 bpath, err := filepath.Abs(filepath.Join("testdata", "b.go"))
582 if err != nil {
583 t.Fatal(err)
584 }
585
586 jsonExport, _ := FindPkg("encoding/json", "testdata")
587 if jsonExport == "" {
588 t.Fatalf("no export data found for encoding/json")
589 }
590
591 compilePkg(t, "testdata", "a.go", testoutdir, map[string]string{"encoding/json": jsonExport}, apkg(testoutdir))
592 compile(t, testoutdir, bpath, testoutdir, map[string]string{apkg(testoutdir): filepath.Join(testoutdir, "a.o")})
593
594
595 pkg := importPkg(t, "./testdata/b", tmpdir)
596
597
598 for _, imp := range pkg.Imports() {
599 if imp.Name() == "" {
600 t.Errorf("no name for %s package", imp.Path())
601 }
602 }
603 }
604
605 func TestIssue13898(t *testing.T) {
606
607 needsCompiler(t, "gc")
608 testenv.NeedsGoBuild(t)
609
610
611 imports := make(map[string]*types.Package)
612 _, err := Import(imports, "go/internal/gcimporter", ".", nil)
613 if err != nil {
614 t.Fatal(err)
615 }
616
617
618 var goTypesPkg *types.Package
619 for path, pkg := range imports {
620 if path == "go/types" {
621 goTypesPkg = pkg
622 break
623 }
624 }
625 if goTypesPkg == nil {
626 t.Fatal("go/types not found")
627 }
628
629
630 obj := lookupObj(t, goTypesPkg.Scope(), "Object")
631 typ, ok := aliases.Unalias(obj.Type()).(*types.Named)
632 if !ok {
633 t.Fatalf("go/types.Object type is %v; wanted named type", typ)
634 }
635
636
637 m, index, indirect := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
638 if m == nil {
639 t.Fatalf("go/types.Object.Pkg not found (index = %v, indirect = %v)", index, indirect)
640 }
641
642
643 if m.Pkg().Path() != "go/types" {
644 t.Fatalf("found %v; want go/types", m.Pkg())
645 }
646 }
647
648 func TestIssue15517(t *testing.T) {
649
650 needsCompiler(t, "gc")
651
652
653
654 if runtime.GOOS == "windows" {
655 t.Skip("avoid dealing with relative paths/drive letters on windows")
656 }
657
658 tmpdir := mktmpdir(t)
659 defer os.RemoveAll(tmpdir)
660
661 compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"), nil)
662
663
664
665
666
667
668
669
670
671
672
673
674
675 imports := make(map[string]*types.Package)
676 for i := 0; i < 3; i++ {
677 if _, err := Import(imports, "./././testdata/p", tmpdir, nil); err != nil {
678 t.Fatal(err)
679 }
680 }
681 }
682
683 func TestIssue15920(t *testing.T) {
684
685 needsCompiler(t, "gc")
686
687
688
689 if runtime.GOOS == "windows" {
690 t.Skip("avoid dealing with relative paths/drive letters on windows")
691 }
692
693 compileAndImportPkg(t, "issue15920")
694 }
695
696 func TestIssue20046(t *testing.T) {
697
698 needsCompiler(t, "gc")
699
700
701
702 if runtime.GOOS == "windows" {
703 t.Skip("avoid dealing with relative paths/drive letters on windows")
704 }
705
706
707 pkg := compileAndImportPkg(t, "issue20046")
708 obj := lookupObj(t, pkg.Scope(), "V")
709 if m, index, indirect := types.LookupFieldOrMethod(obj.Type(), false, nil, "M"); m == nil {
710 t.Fatalf("V.M not found (index = %v, indirect = %v)", index, indirect)
711 }
712 }
713
714 func TestIssue25301(t *testing.T) {
715
716 needsCompiler(t, "gc")
717
718
719
720 if runtime.GOOS == "windows" {
721 t.Skip("avoid dealing with relative paths/drive letters on windows")
722 }
723
724 compileAndImportPkg(t, "issue25301")
725 }
726
727 func TestIssue51836(t *testing.T) {
728
729 needsCompiler(t, "gc")
730
731
732
733 if runtime.GOOS == "windows" {
734 t.Skip("avoid dealing with relative paths/drive letters on windows")
735 }
736
737 tmpdir := mktmpdir(t)
738 defer os.RemoveAll(tmpdir)
739 testoutdir := filepath.Join(tmpdir, "testdata")
740
741 dir := filepath.Join("testdata", "issue51836")
742
743
744
745 bpath, err := filepath.Abs(filepath.Join(dir, "aa.go"))
746 if err != nil {
747 t.Fatal(err)
748 }
749 compilePkg(t, dir, "a.go", testoutdir, nil, apkg(testoutdir))
750 compile(t, testoutdir, bpath, testoutdir, map[string]string{apkg(testoutdir): filepath.Join(testoutdir, "a.o")})
751
752
753 _ = importPkg(t, "./testdata/aa", tmpdir)
754 }
755
756 func TestIssue61561(t *testing.T) {
757 const src = `package p
758
759 type I[P any] interface {
760 m(P)
761 n() P
762 }
763
764 type J = I[int]
765
766 type StillBad[P any] *interface{b(P)}
767
768 type K = StillBad[string]
769 `
770 fset := token.NewFileSet()
771 f, err := goparser.ParseFile(fset, "p.go", src, 0)
772 if f == nil {
773
774
775 t.Fatalf("ParseFile returned nil file. Err: %v", err)
776 }
777
778 config := &types.Config{}
779 pkg1, err := config.Check("p", fset, []*ast.File{f}, nil)
780 if err != nil {
781 t.Fatal(err)
782 }
783
784
785 data, err := IExportShallow(fset, pkg1, nil)
786 if err != nil {
787 t.Fatalf("export: %v", err)
788 }
789
790
791 imports := make(map[string]*types.Package)
792 pkg2, err := IImportShallow(fset, GetPackagesFromMap(imports), data, "p", nil)
793 if err != nil {
794 t.Fatalf("import: %v", err)
795 }
796
797 insts := []types.Type{
798 pkg2.Scope().Lookup("J").Type(),
799
800
801
802
803
804 }
805
806
807 for _, inst := range insts {
808 var wg sync.WaitGroup
809 for i := 0; i < 2; i++ {
810 wg.Add(1)
811 go func() {
812 defer wg.Done()
813 _ = types.NewMethodSet(inst)
814 }()
815 }
816 wg.Wait()
817 }
818 }
819
820 func TestIssue57015(t *testing.T) {
821
822 needsCompiler(t, "gc")
823
824
825
826 if runtime.GOOS == "windows" {
827 t.Skip("avoid dealing with relative paths/drive letters on windows")
828 }
829
830 compileAndImportPkg(t, "issue57015")
831 }
832
833
834
835
836
837
838
839
840
841 func TestExportInvalid(t *testing.T) {
842
843 tests := []struct {
844 name string
845 src string
846 objName string
847 }{
848
849
850
851
852 {"issue 57729", `package p; func () Foo() {}`, "Foo"},
853
854
855
856 {"issue 60605", `package p; const EPSILON float64 = 1e-`, "EPSILON"},
857
858
859 {"issue 60891", `package p; type I[P any] int; const C I[struct{}] = 42`, "C"},
860 }
861
862 for _, test := range tests {
863 t.Run(test.name, func(t *testing.T) {
864
865 fset := token.NewFileSet()
866
867 f, err := goparser.ParseFile(fset, "p.go", test.src, 0)
868 if f == nil {
869
870
871 t.Fatalf("ParseFile returned nil file. Err: %v", err)
872 }
873
874
875 config := &types.Config{
876 Error: func(err error) { t.Log(err) },
877 }
878 pkg1, _ := config.Check("p", fset, []*ast.File{f}, nil)
879
880
881
882 data, err := IExportShallow(fset, pkg1, nil)
883 if err != nil {
884 t.Fatalf("export: %v", err)
885 }
886
887
888 imports := make(map[string]*types.Package)
889 pkg2, err := IImportShallow(fset, GetPackagesFromMap(imports), data, "p", nil)
890 if err != nil {
891 t.Fatalf("import: %v", err)
892 }
893
894
895
896 hasObj1 := pkg1.Scope().Lookup(test.objName) != nil
897 hasObj2 := pkg2.Scope().Lookup(test.objName) != nil
898 if hasObj1 != hasObj2 {
899 t.Errorf("export+import changed Lookup(%q)!=nil: was %t, became %t", test.objName, hasObj1, hasObj2)
900 }
901 })
902 }
903 }
904
905 func TestIssue58296(t *testing.T) {
906
907
908
909
910
911
912
913 needsCompiler(t, "gc")
914 testenv.NeedsGoBuild(t)
915
916
917
918 if runtime.GOOS == "windows" {
919 t.Skip("avoid dealing with relative paths/drive letters on windows")
920 }
921
922 tmpdir := mktmpdir(t)
923 defer os.RemoveAll(tmpdir)
924 testoutdir := filepath.Join(tmpdir, "testdata")
925
926 apkg := filepath.Join(testoutdir, "a")
927 bpkg := filepath.Join(testoutdir, "b")
928 cpkg := filepath.Join(testoutdir, "c")
929
930 srcdir := filepath.Join("testdata", "issue58296")
931 compilePkg(t, filepath.Join(srcdir, "a"), "a.go", testoutdir, nil, apkg)
932 compilePkg(t, filepath.Join(srcdir, "b"), "b.go", testoutdir, map[string]string{apkg: filepath.Join(testoutdir, "a.o")}, bpkg)
933 compilePkg(t, filepath.Join(srcdir, "c"), "c.go", testoutdir, map[string]string{bpkg: filepath.Join(testoutdir, "b.o")}, cpkg)
934
935
936
937 imports := map[string]*types.Package{
938 apkg: types.NewPackage(apkg, "a"),
939 bpkg: types.NewPackage(bpkg, "b"),
940 }
941
942
943 pkg, err := Import(imports, "./c", testoutdir, nil)
944 if err != nil {
945 t.Fatal(err)
946 }
947
948 var names []string
949 for _, imp := range pkg.Imports() {
950 names = append(names, imp.Name())
951 }
952 sort.Strings(names)
953
954 if got, want := strings.Join(names, ","), "a,b"; got != want {
955 t.Errorf("got imports %v for package c. wanted %v", names, want)
956 }
957 }
958
959
960 func apkg(testoutdir string) string {
961 apkg := testoutdir + "/a"
962 if os.PathSeparator != '/' {
963 apkg = strings.ReplaceAll(apkg, string(os.PathSeparator), "/")
964 }
965 return apkg
966 }
967
968 func importPkg(t *testing.T, path, srcDir string) *types.Package {
969 pkg, err := Import(make(map[string]*types.Package), path, srcDir, nil)
970 if err != nil {
971 t.Fatal(err)
972 }
973 return pkg
974 }
975
976 func compileAndImportPkg(t *testing.T, name string) *types.Package {
977 tmpdir := mktmpdir(t)
978 defer os.RemoveAll(tmpdir)
979 compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"), nil)
980 return importPkg(t, "./testdata/"+name, tmpdir)
981 }
982
983 func lookupObj(t *testing.T, scope *types.Scope, name string) types.Object {
984 if obj := scope.Lookup(name); obj != nil {
985 return obj
986 }
987 t.Fatalf("%s not found", name)
988 return nil
989 }
990
View as plain text