Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / refactor / rename / rename_test.go
1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package rename
6
7 import (
8         "bytes"
9         "fmt"
10         "go/build"
11         "go/token"
12         "io/ioutil"
13         "os"
14         "os/exec"
15         "path/filepath"
16         "regexp"
17         "runtime"
18         "strings"
19         "testing"
20
21         "golang.org/x/tools/go/buildutil"
22         "golang.org/x/tools/internal/testenv"
23 )
24
25 // TODO(adonovan): test reported source positions, somehow.
26
27 func TestConflicts(t *testing.T) {
28         defer func(savedWriteFile func(string, []byte) error, savedReportError func(token.Position, string)) {
29                 writeFile = savedWriteFile
30                 reportError = savedReportError
31         }(writeFile, reportError)
32         writeFile = func(string, []byte) error { return nil }
33
34         var ctxt *build.Context
35         for _, test := range []struct {
36                 ctxt             *build.Context // nil => use previous
37                 offset, from, to string         // values of the -offset/-from and -to flags
38                 want             string         // regexp to match conflict errors, or "OK"
39         }{
40                 // init() checks
41                 {
42                         ctxt: fakeContext(map[string][]string{
43                                 "fmt": {`package fmt; type Stringer interface { String() }`},
44                                 "main": {`
45 package main
46
47 import foo "fmt"
48
49 var v foo.Stringer
50
51 func f() { v.String(); f() }
52 `,
53                                         `package main; var w int`},
54                         }),
55                         from: "main.v", to: "init",
56                         want: `you cannot have a var at package level named "init"`,
57                 },
58                 {
59                         from: "main.f", to: "init",
60                         want: `renaming this func "f" to "init" would make it a package initializer.*` +
61                                 `but references to it exist`,
62                 },
63                 {
64                         from: "/go/src/main/0.go::foo", to: "init",
65                         want: `"init" is not a valid imported package name`,
66                 },
67
68                 // Export checks
69                 {
70                         from: "fmt.Stringer", to: "stringer",
71                         want: `renaming this type "Stringer" to "stringer" would make it unexported.*` +
72                                 `breaking references from packages such as "main"`,
73                 },
74                 {
75                         from: "(fmt.Stringer).String", to: "string",
76                         want: `renaming this method "String" to "string" would make it unexported.*` +
77                                 `breaking references from packages such as "main"`,
78                 },
79
80                 // Lexical scope checks
81                 {
82                         // file/package conflict, same file
83                         from: "main.v", to: "foo",
84                         want: `renaming this var "v" to "foo" would conflict.*` +
85                                 `with this imported package name`,
86                 },
87                 {
88                         // file/package conflict, same file
89                         from: "main::foo", to: "v",
90                         want: `renaming this imported package name "foo" to "v" would conflict.*` +
91                                 `with this package member var`,
92                 },
93                 {
94                         // file/package conflict, different files
95                         from: "main.w", to: "foo",
96                         want: `renaming this var "w" to "foo" would conflict.*` +
97                                 `with this imported package name`,
98                 },
99                 {
100                         // file/package conflict, different files
101                         from: "main::foo", to: "w",
102                         want: `renaming this imported package name "foo" to "w" would conflict.*` +
103                                 `with this package member var`,
104                 },
105                 {
106                         ctxt: main(`
107 package main
108
109 var x, z int
110
111 func f(y int) {
112         print(x)
113         print(y)
114 }
115
116 func g(w int) {
117         print(x)
118         x := 1
119         print(x)
120 }`),
121                         from: "main.x", to: "y",
122                         want: `renaming this var "x" to "y".*` +
123                                 `would cause this reference to become shadowed.*` +
124                                 `by this intervening var definition`,
125                 },
126                 {
127                         from: "main.g::x", to: "w",
128                         want: `renaming this var "x" to "w".*` +
129                                 `conflicts with var in same block`,
130                 },
131                 {
132                         from: "main.f::y", to: "x",
133                         want: `renaming this var "y" to "x".*` +
134                                 `would shadow this reference.*` +
135                                 `to the var declared here`,
136                 },
137                 {
138                         from: "main.g::w", to: "x",
139                         want: `renaming this var "w" to "x".*` +
140                                 `conflicts with var in same block`,
141                 },
142                 {
143                         from: "main.z", to: "y", want: "OK",
144                 },
145
146                 // Label checks
147                 {
148                         ctxt: main(`
149 package main
150
151 func f() {
152 foo:
153         goto foo
154 bar:
155         goto bar
156         func(x int) {
157         wiz:
158                 goto wiz
159         }(0)
160 }
161 `),
162                         from: "main.f::foo", to: "bar",
163                         want: `renaming this label "foo" to "bar".*` +
164                                 `would conflict with this one`,
165                 },
166                 {
167                         from: "main.f::foo", to: "wiz", want: "OK",
168                 },
169                 {
170                         from: "main.f::wiz", to: "x", want: "OK",
171                 },
172                 {
173                         from: "main.f::x", to: "wiz", want: "OK",
174                 },
175                 {
176                         from: "main.f::wiz", to: "foo", want: "OK",
177                 },
178
179                 // Struct fields
180                 {
181                         ctxt: main(`
182 package main
183
184 type U struct { u int }
185 type V struct { v int }
186
187 func (V) x() {}
188
189 type W (struct {
190         U
191         V
192         w int
193 })
194
195 func f() {
196         var w W
197         print(w.u) // NB: there is no selection of w.v
198         var _ struct { yy, zz int }
199 }
200 `),
201                         // field/field conflict in named struct declaration
202                         from: "(main.W).U", to: "w",
203                         want: `renaming this field "U" to "w".*` +
204                                 `would conflict with this field`,
205                 },
206                 {
207                         // rename type used as embedded field
208                         // => rename field
209                         // => field/field conflict
210                         // This is an entailed renaming;
211                         // it would be nice if we checked source positions.
212                         from: "main.U", to: "w",
213                         want: `renaming this field "U" to "w".*` +
214                                 `would conflict with this field`,
215                 },
216                 {
217                         // field/field conflict in unnamed struct declaration
218                         from: "main.f::zz", to: "yy",
219                         want: `renaming this field "zz" to "yy".*` +
220                                 `would conflict with this field`,
221                 },
222
223                 // Now we test both directions of (u,v) (u,w) (v,w) (u,x) (v,x).
224                 // Too bad we don't test position info...
225                 {
226                         // field/field ambiguity at same promotion level ('from' selection)
227                         from: "(main.U).u", to: "v",
228                         want: `renaming this field "u" to "v".*` +
229                                 `would make this reference ambiguous.*` +
230                                 `with this field`,
231                 },
232                 {
233                         // field/field ambiguity at same promotion level ('to' selection)
234                         from: "(main.V).v", to: "u",
235                         want: `renaming this field "v" to "u".*` +
236                                 `would make this reference ambiguous.*` +
237                                 `with this field`,
238                 },
239                 {
240                         // field/method conflict at different promotion level ('from' selection)
241                         from: "(main.U).u", to: "w",
242                         want: `renaming this field "u" to "w".*` +
243                                 `would change the referent of this selection.*` +
244                                 `of this field`,
245                 },
246                 {
247                         // field/field shadowing at different promotion levels ('to' selection)
248                         from: "(main.W).w", to: "u",
249                         want: `renaming this field "w" to "u".*` +
250                                 `would shadow this selection.*` +
251                                 `of the field declared here`,
252                 },
253                 {
254                         from: "(main.V).v", to: "w",
255                         want: "OK", // since no selections are made ambiguous
256                 },
257                 {
258                         from: "(main.W).w", to: "v",
259                         want: "OK", // since no selections are made ambiguous
260                 },
261                 {
262                         // field/method ambiguity at same promotion level ('from' selection)
263                         from: "(main.U).u", to: "x",
264                         want: `renaming this field "u" to "x".*` +
265                                 `would make this reference ambiguous.*` +
266                                 `with this method`,
267                 },
268                 {
269                         // field/field ambiguity at same promotion level ('to' selection)
270                         from: "(main.V).x", to: "u",
271                         want: `renaming this method "x" to "u".*` +
272                                 `would make this reference ambiguous.*` +
273                                 `with this field`,
274                 },
275                 {
276                         // field/method conflict at named struct declaration
277                         from: "(main.V).v", to: "x",
278                         want: `renaming this field "v" to "x".*` +
279                                 `would conflict with this method`,
280                 },
281                 {
282                         // field/method conflict at named struct declaration
283                         from: "(main.V).x", to: "v",
284                         want: `renaming this method "x" to "v".*` +
285                                 `would conflict with this field`,
286                 },
287
288                 // Methods
289                 {
290                         ctxt: main(`
291 package main
292 type C int
293 func (C) f()
294 func (C) g()
295 type D int
296 func (*D) f()
297 func (*D) g()
298 type I interface { f(); g() }
299 type J interface { I; h() }
300 var _ I = new(D)
301 var _ interface {f()} = C(0)
302 `),
303                         from: "(main.I).f", to: "g",
304                         want: `renaming this interface method "f" to "g".*` +
305                                 `would conflict with this method`,
306                 },
307                 {
308                         from: `("main".I).f`, to: "h", // NB: exercises quoted import paths too
309                         want: `renaming this interface method "f" to "h".*` +
310                                 `would conflict with this method.*` +
311                                 `in named interface type "J"`,
312                 },
313                 {
314                         // type J interface { h; h() } is not a conflict, amusingly.
315                         from: "main.I", to: "h",
316                         want: `OK`,
317                 },
318                 {
319                         from: "(main.J).h", to: "f",
320                         want: `renaming this interface method "h" to "f".*` +
321                                 `would conflict with this method`,
322                 },
323                 {
324                         from: "(main.C).f", to: "e",
325                         want: `renaming this method "f" to "e".*` +
326                                 `would make main.C no longer assignable to interface{f..}.*` +
327                                 `(rename interface{f..}.f if you intend to change both types)`,
328                 },
329                 {
330                         from: "(main.D).g", to: "e",
331                         want: `renaming this method "g" to "e".*` +
332                                 `would make \*main.D no longer assignable to interface I.*` +
333                                 `(rename main.I.g if you intend to change both types)`,
334                 },
335                 {
336                         from: "(main.I).f", to: "e",
337                         want: `OK`,
338                 },
339                 // Indirect C/I method coupling via another concrete type D.
340                 {
341                         ctxt: main(`
342 package main
343 type I interface { f() }
344 type C int
345 func (C) f()
346 type D struct{C}
347 var _ I = D{}
348 `),
349                         from: "(main.C).f", to: "F",
350                         want: `renaming this method "f" to "F".*` +
351                                 `would make main.D no longer assignable to interface I.*` +
352                                 `(rename main.I.f if you intend to change both types)`,
353                 },
354                 // Renaming causes promoted method to become shadowed; C no longer satisfies I.
355                 {
356                         ctxt: main(`
357 package main
358 type I interface { f() }
359 type C struct { I }
360 func (C) g() int
361 var _ I = C{}
362 `),
363                         from: "main.I.f", to: "g",
364                         want: `renaming this method "f" to "g".*` +
365                                 `would change the g method of main.C invoked via interface main.I.*` +
366                                 `from \(main.I\).g.*` +
367                                 `to \(main.C\).g`,
368                 },
369                 // Renaming causes promoted method to become ambiguous; C no longer satisfies I.
370                 {
371                         ctxt: main(`
372 package main
373 type I interface{f()}
374 type C int
375 func (C) f()
376 type D int
377 func (D) g()
378 type E struct{C;D}
379 var _ I = E{}
380 `),
381                         from: "main.I.f", to: "g",
382                         want: `renaming this method "f" to "g".*` +
383                                 `would make the g method of main.E invoked via interface main.I ambiguous.*` +
384                                 `with \(main.D\).g`,
385                 },
386         } {
387                 var conflicts []string
388                 reportError = func(posn token.Position, message string) {
389                         conflicts = append(conflicts, message)
390                 }
391                 if test.ctxt != nil {
392                         ctxt = test.ctxt
393                 }
394                 err := Main(ctxt, test.offset, test.from, test.to)
395                 var prefix string
396                 if test.offset == "" {
397                         prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to)
398                 } else {
399                         prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to)
400                 }
401                 if err == ConflictError {
402                         got := strings.Join(conflicts, "\n")
403                         if false {
404                                 t.Logf("%s: %s", prefix, got)
405                         }
406                         pattern := "(?s:" + test.want + ")" // enable multi-line matching
407                         if !regexp.MustCompile(pattern).MatchString(got) {
408                                 t.Errorf("%s: conflict does not match pattern:\n"+
409                                         "Conflict:\t%s\n"+
410                                         "Pattern: %s",
411                                         prefix, got, test.want)
412                         }
413                 } else if err != nil {
414                         t.Errorf("%s: unexpected error: %s", prefix, err)
415                 } else if test.want != "OK" {
416                         t.Errorf("%s: unexpected success, want conflicts matching:\n%s",
417                                 prefix, test.want)
418                 }
419         }
420 }
421
422 func TestInvalidIdentifiers(t *testing.T) {
423         ctxt := fakeContext(map[string][]string{
424                 "main": {`
425 package main
426
427 func f() { }
428 `}})
429
430         for _, test := range []struct {
431                 from, to string // values of the -offset/-from and -to flags
432                 want     string // expected error message
433         }{
434                 {
435                         from: "main.f", to: "_",
436                         want: `-to "_": not a valid identifier`,
437                 },
438                 {
439                         from: "main.f", to: "123",
440                         want: `-to "123": not a valid identifier`,
441                 },
442                 {
443                         from: "main.f", to: "for",
444                         want: `-to "for": not a valid identifier`,
445                 },
446                 {
447                         from: "switch", to: "v",
448                         want: `-from "switch": invalid expression`,
449                 },
450         } {
451                 err := Main(ctxt, "", test.from, test.to)
452                 prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
453                 if err == nil {
454                         t.Errorf("%s: expected error %q", prefix, test.want)
455                 } else if err.Error() != test.want {
456                         t.Errorf("%s: unexpected error\nwant: %s\n got: %s", prefix, test.want, err.Error())
457                 }
458         }
459 }
460
461 func TestRewrites(t *testing.T) {
462         defer func(savedWriteFile func(string, []byte) error) {
463                 writeFile = savedWriteFile
464         }(writeFile)
465
466         var ctxt *build.Context
467         for _, test := range []struct {
468                 ctxt             *build.Context    // nil => use previous
469                 offset, from, to string            // values of the -from/-offset and -to flags
470                 want             map[string]string // contents of updated files
471         }{
472                 // Elimination of renaming import.
473                 {
474                         ctxt: fakeContext(map[string][]string{
475                                 "foo": {`package foo; type T int`},
476                                 "main": {`package main
477
478 import foo2 "foo"
479
480 var _ foo2.T
481 `},
482                         }),
483                         from: "main::foo2", to: "foo",
484                         want: map[string]string{
485                                 "/go/src/main/0.go": `package main
486
487 import "foo"
488
489 var _ foo.T
490 `,
491                         },
492                 },
493                 // Introduction of renaming import.
494                 {
495                         ctxt: fakeContext(map[string][]string{
496                                 "foo": {`package foo; type T int`},
497                                 "main": {`package main
498
499 import "foo"
500
501 var _ foo.T
502 `},
503                         }),
504                         offset: "/go/src/main/0.go:#36", to: "foo2", // the "foo" in foo.T
505                         want: map[string]string{
506                                 "/go/src/main/0.go": `package main
507
508 import foo2 "foo"
509
510 var _ foo2.T
511 `,
512                         },
513                 },
514                 // Renaming of package-level member.
515                 {
516                         from: "foo.T", to: "U",
517                         want: map[string]string{
518                                 "/go/src/main/0.go": `package main
519
520 import "foo"
521
522 var _ foo.U
523 `,
524                                 "/go/src/foo/0.go": `package foo
525
526 type U int
527 `,
528                         },
529                 },
530                 // Rename package-level func plus doc
531                 {
532                         ctxt: main(`package main
533
534 // Foo is a no-op.
535 // Calling Foo does nothing.
536 func Foo() {
537 }
538 `),
539                         from: "main.Foo", to: "FooBar",
540                         want: map[string]string{
541                                 "/go/src/main/0.go": `package main
542
543 // FooBar is a no-op.
544 // Calling FooBar does nothing.
545 func FooBar() {
546 }
547 `,
548                         },
549                 },
550                 // Rename method plus doc
551                 {
552                         ctxt: main(`package main
553
554 type Foo struct{}
555
556 // Bar does nothing.
557 func (Foo) Bar() {
558 }
559 `),
560                         from: "main.Foo.Bar", to: "Baz",
561                         want: map[string]string{
562                                 "/go/src/main/0.go": `package main
563
564 type Foo struct{}
565
566 // Baz does nothing.
567 func (Foo) Baz() {
568 }
569 `,
570                         },
571                 },
572                 // Rename type spec plus doc
573                 {
574                         ctxt: main(`package main
575
576 type (
577         // Test but not Testing.
578         Test struct{}
579 )
580 `),
581                         from: "main.Test", to: "Type",
582                         want: map[string]string{
583                                 "/go/src/main/0.go": `package main
584
585 type (
586         // Type but not Testing.
587         Type struct{}
588 )
589 `,
590                         },
591                 },
592                 // Rename type in gen decl plus doc
593                 {
594                         ctxt: main(`package main
595
596 // T is a test type.
597 type T struct{}
598 `),
599                         from: "main.T", to: "Type",
600                         want: map[string]string{
601                                 "/go/src/main/0.go": `package main
602
603 // Type is a test type.
604 type Type struct{}
605 `,
606                         },
607                 },
608                 // Rename value spec with doc
609                 {
610                         ctxt: main(`package main
611
612 const (
613         // C is the speed of light.
614         C = 2.998e8
615 )
616 `),
617                         from: "main.C", to: "Lightspeed",
618                         want: map[string]string{
619                                 "/go/src/main/0.go": `package main
620
621 const (
622         // Lightspeed is the speed of light.
623         Lightspeed = 2.998e8
624 )
625 `,
626                         },
627                 },
628                 // Rename value inside gen decl with doc
629                 {
630                         ctxt: main(`package main
631
632 var out *string
633 `),
634                         from: "main.out", to: "discard",
635                         want: map[string]string{
636                                 "/go/src/main/0.go": `package main
637
638 var discard *string
639 `,
640                         },
641                 },
642                 // Rename field plus doc
643                 {
644                         ctxt: main(`package main
645
646 type Struct struct {
647         // Field is a struct field.
648         Field string
649 }
650 `),
651                         from: "main.Struct.Field", to: "Foo",
652                         want: map[string]string{
653                                 "/go/src/main/0.go": `package main
654
655 type Struct struct {
656         // Foo is a struct field.
657         Foo string
658 }
659 `,
660                         },
661                 },
662                 // Label renamings.
663                 {
664                         ctxt: main(`package main
665 func f() {
666 loop:
667         loop := 0
668         go func() {
669         loop:
670                 goto loop
671         }()
672         loop++
673         goto loop
674 }
675 `),
676                         offset: "/go/src/main/0.go:#25", to: "loop2", // def of outer label "loop"
677                         want: map[string]string{
678                                 "/go/src/main/0.go": `package main
679
680 func f() {
681 loop2:
682         loop := 0
683         go func() {
684         loop:
685                 goto loop
686         }()
687         loop++
688         goto loop2
689 }
690 `,
691                         },
692                 },
693                 {
694                         offset: "/go/src/main/0.go:#70", to: "loop2", // ref to inner label "loop"
695                         want: map[string]string{
696                                 "/go/src/main/0.go": `package main
697
698 func f() {
699 loop:
700         loop := 0
701         go func() {
702         loop2:
703                 goto loop2
704         }()
705         loop++
706         goto loop
707 }
708 `,
709                         },
710                 },
711                 // Renaming of type used as embedded field.
712                 {
713                         ctxt: main(`package main
714
715 type T int
716 type U struct { T }
717
718 var _ = U{}.T
719 `),
720                         from: "main.T", to: "T2",
721                         want: map[string]string{
722                                 "/go/src/main/0.go": `package main
723
724 type T2 int
725 type U struct{ T2 }
726
727 var _ = U{}.T2
728 `,
729                         },
730                 },
731                 // Renaming of embedded field.
732                 {
733                         ctxt: main(`package main
734
735 type T int
736 type U struct { T }
737
738 var _ = U{}.T
739 `),
740                         offset: "/go/src/main/0.go:#58", to: "T2", // T in "U{}.T"
741                         want: map[string]string{
742                                 "/go/src/main/0.go": `package main
743
744 type T2 int
745 type U struct{ T2 }
746
747 var _ = U{}.T2
748 `,
749                         },
750                 },
751                 // Renaming of pointer embedded field.
752                 {
753                         ctxt: main(`package main
754
755 type T int
756 type U struct { *T }
757
758 var _ = U{}.T
759 `),
760                         offset: "/go/src/main/0.go:#59", to: "T2", // T in "U{}.T"
761                         want: map[string]string{
762                                 "/go/src/main/0.go": `package main
763
764 type T2 int
765 type U struct{ *T2 }
766
767 var _ = U{}.T2
768 `,
769                         },
770                 },
771
772                 // Lexical scope tests.
773                 {
774                         ctxt: main(`package main
775
776 var y int
777
778 func f() {
779         print(y)
780         y := ""
781         print(y)
782 }
783 `),
784                         from: "main.y", to: "x",
785                         want: map[string]string{
786                                 "/go/src/main/0.go": `package main
787
788 var x int
789
790 func f() {
791         print(x)
792         y := ""
793         print(y)
794 }
795 `,
796                         },
797                 },
798                 {
799                         from: "main.f::y", to: "x",
800                         want: map[string]string{
801                                 "/go/src/main/0.go": `package main
802
803 var y int
804
805 func f() {
806         print(y)
807         x := ""
808         print(x)
809 }
810 `,
811                         },
812                 },
813                 // Renaming of typeswitch vars (a corner case).
814                 {
815                         ctxt: main(`package main
816
817 func f(z interface{}) {
818         switch y := z.(type) {
819         case int:
820                 print(y)
821         default:
822                 print(y)
823         }
824 }
825 `),
826                         offset: "/go/src/main/0.go:#46", to: "x", // def of y
827                         want: map[string]string{
828                                 "/go/src/main/0.go": `package main
829
830 func f(z interface{}) {
831         switch x := z.(type) {
832         case int:
833                 print(x)
834         default:
835                 print(x)
836         }
837 }
838 `},
839                 },
840                 {
841                         offset: "/go/src/main/0.go:#81", to: "x", // ref of y in case int
842                         want: map[string]string{
843                                 "/go/src/main/0.go": `package main
844
845 func f(z interface{}) {
846         switch x := z.(type) {
847         case int:
848                 print(x)
849         default:
850                 print(x)
851         }
852 }
853 `},
854                 },
855                 {
856                         offset: "/go/src/main/0.go:#102", to: "x", // ref of y in default case
857                         want: map[string]string{
858                                 "/go/src/main/0.go": `package main
859
860 func f(z interface{}) {
861         switch x := z.(type) {
862         case int:
863                 print(x)
864         default:
865                 print(x)
866         }
867 }
868 `},
869                 },
870
871                 // Renaming of embedded field that is a qualified reference.
872                 // (Regression test for bug 8924.)
873                 {
874                         ctxt: fakeContext(map[string][]string{
875                                 "foo": {`package foo; type T int`},
876                                 "main": {`package main
877
878 import "foo"
879
880 type _ struct{ *foo.T }
881 `},
882                         }),
883                         offset: "/go/src/main/0.go:#48", to: "U", // the "T" in *foo.T
884                         want: map[string]string{
885                                 "/go/src/foo/0.go": `package foo
886
887 type U int
888 `,
889                                 "/go/src/main/0.go": `package main
890
891 import "foo"
892
893 type _ struct{ *foo.U }
894 `,
895                         },
896                 },
897
898                 // Renaming of embedded field that is a qualified reference with the '-from' flag.
899                 // (Regression test for bug 12038.)
900                 {
901                         ctxt: fakeContext(map[string][]string{
902                                 "foo": {`package foo; type T int`},
903                                 "main": {`package main
904
905 import "foo"
906
907 type V struct{ *foo.T }
908 `},
909                         }),
910                         from: "(main.V).T", to: "U", // the "T" in *foo.T
911                         want: map[string]string{
912                                 "/go/src/foo/0.go": `package foo
913
914 type U int
915 `,
916                                 "/go/src/main/0.go": `package main
917
918 import "foo"
919
920 type V struct{ *foo.U }
921 `,
922                         },
923                 },
924                 {
925                         ctxt: fakeContext(map[string][]string{
926                                 "foo": {`package foo; type T int`},
927                                 "main": {`package main
928
929 import "foo"
930
931 type V struct{ foo.T }
932 `},
933                         }),
934                         from: "(main.V).T", to: "U", // the "T" in *foo.T
935                         want: map[string]string{
936                                 "/go/src/foo/0.go": `package foo
937
938 type U int
939 `,
940                                 "/go/src/main/0.go": `package main
941
942 import "foo"
943
944 type V struct{ foo.U }
945 `,
946                         },
947                 },
948
949                 // Interface method renaming.
950                 {
951                         ctxt: fakeContext(map[string][]string{
952                                 "main": {`
953 package main
954 type I interface {
955         f()
956 }
957 type J interface { f(); g() }
958 type A int
959 func (A) f()
960 type B int
961 func (B) f()
962 func (B) g()
963 type C int
964 func (C) f()
965 func (C) g()
966 var _, _ I = A(0), B(0)
967 var _, _ J = B(0), C(0)
968 `,
969                                 },
970                         }),
971                         offset: "/go/src/main/0.go:#34", to: "F", // abstract method I.f
972                         want: map[string]string{
973                                 "/go/src/main/0.go": `package main
974
975 type I interface {
976         F()
977 }
978 type J interface {
979         F()
980         g()
981 }
982 type A int
983
984 func (A) F()
985
986 type B int
987
988 func (B) F()
989 func (B) g()
990
991 type C int
992
993 func (C) F()
994 func (C) g()
995
996 var _, _ I = A(0), B(0)
997 var _, _ J = B(0), C(0)
998 `,
999                         },
1000                 },
1001                 {
1002                         offset: "/go/src/main/0.go:#59", to: "F", // abstract method J.f
1003                         want: map[string]string{
1004                                 "/go/src/main/0.go": `package main
1005
1006 type I interface {
1007         F()
1008 }
1009 type J interface {
1010         F()
1011         g()
1012 }
1013 type A int
1014
1015 func (A) F()
1016
1017 type B int
1018
1019 func (B) F()
1020 func (B) g()
1021
1022 type C int
1023
1024 func (C) F()
1025 func (C) g()
1026
1027 var _, _ I = A(0), B(0)
1028 var _, _ J = B(0), C(0)
1029 `,
1030                         },
1031                 },
1032                 {
1033                         offset: "/go/src/main/0.go:#64", to: "G", // abstract method J.g
1034                         want: map[string]string{
1035                                 "/go/src/main/0.go": `package main
1036
1037 type I interface {
1038         f()
1039 }
1040 type J interface {
1041         f()
1042         G()
1043 }
1044 type A int
1045
1046 func (A) f()
1047
1048 type B int
1049
1050 func (B) f()
1051 func (B) G()
1052
1053 type C int
1054
1055 func (C) f()
1056 func (C) G()
1057
1058 var _, _ I = A(0), B(0)
1059 var _, _ J = B(0), C(0)
1060 `,
1061                         },
1062                 },
1063                 // Indirect coupling of I.f to C.f from D->I assignment and anonymous field of D.
1064                 {
1065                         ctxt: fakeContext(map[string][]string{
1066                                 "main": {`
1067 package main
1068 type I interface {
1069         f()
1070 }
1071 type C int
1072 func (C) f()
1073 type D struct{C}
1074 var _ I = D{}
1075 `,
1076                                 },
1077                         }),
1078                         offset: "/go/src/main/0.go:#34", to: "F", // abstract method I.f
1079                         want: map[string]string{
1080                                 "/go/src/main/0.go": `package main
1081
1082 type I interface {
1083         F()
1084 }
1085 type C int
1086
1087 func (C) F()
1088
1089 type D struct{ C }
1090
1091 var _ I = D{}
1092 `,
1093                         },
1094                 },
1095                 // Interface embedded in struct.  No conflict if C need not satisfy I.
1096                 {
1097                         ctxt: fakeContext(map[string][]string{
1098                                 "main": {`
1099 package main
1100 type I interface {
1101         f()
1102 }
1103 type C struct{I}
1104 func (C) g() int
1105 var _ int = C{}.g()
1106 `,
1107                                 },
1108                         }),
1109                         offset: "/go/src/main/0.go:#34", to: "g", // abstract method I.f
1110                         want: map[string]string{
1111                                 "/go/src/main/0.go": `package main
1112
1113 type I interface {
1114         g()
1115 }
1116 type C struct{ I }
1117
1118 func (C) g() int
1119
1120 var _ int = C{}.g()
1121 `,
1122                         },
1123                 },
1124                 // A type assertion causes method coupling iff signatures match.
1125                 {
1126                         ctxt: fakeContext(map[string][]string{
1127                                 "main": {`package main
1128 type I interface{
1129         f()
1130 }
1131 type J interface{
1132         f()
1133 }
1134 var _ = I(nil).(J)
1135 `,
1136                                 },
1137                         }),
1138                         offset: "/go/src/main/0.go:#32", to: "g", // abstract method I.f
1139                         want: map[string]string{
1140                                 "/go/src/main/0.go": `package main
1141
1142 type I interface {
1143         g()
1144 }
1145 type J interface {
1146         g()
1147 }
1148
1149 var _ = I(nil).(J)
1150 `,
1151                         },
1152                 },
1153                 // Impossible type assertion: no method coupling.
1154                 {
1155                         ctxt: fakeContext(map[string][]string{
1156                                 "main": {`package main
1157 type I interface{
1158         f()
1159 }
1160 type J interface{
1161         f()int
1162 }
1163 var _ = I(nil).(J)
1164 `,
1165                                 },
1166                         }),
1167                         offset: "/go/src/main/0.go:#32", to: "g", // abstract method I.f
1168                         want: map[string]string{
1169                                 "/go/src/main/0.go": `package main
1170
1171 type I interface {
1172         g()
1173 }
1174 type J interface {
1175         f() int
1176 }
1177
1178 var _ = I(nil).(J)
1179 `,
1180                         },
1181                 },
1182                 // Impossible type assertion: no method coupling C.f<->J.f.
1183                 {
1184                         ctxt: fakeContext(map[string][]string{
1185                                 "main": {`package main
1186 type I interface{
1187         f()
1188 }
1189 type C int
1190 func (C) f()
1191 type J interface{
1192         f()int
1193 }
1194 var _ = I(C(0)).(J)
1195 `,
1196                                 },
1197                         }),
1198                         offset: "/go/src/main/0.go:#32", to: "g", // abstract method I.f
1199                         want: map[string]string{
1200                                 "/go/src/main/0.go": `package main
1201
1202 type I interface {
1203         g()
1204 }
1205 type C int
1206
1207 func (C) g()
1208
1209 type J interface {
1210         f() int
1211 }
1212
1213 var _ = I(C(0)).(J)
1214 `,
1215                         },
1216                 },
1217                 // Progress after "soft" type errors (Go issue 14596).
1218                 {
1219                         ctxt: fakeContext(map[string][]string{
1220                                 "main": {`package main
1221
1222 func main() {
1223         var unused, x int
1224         print(x)
1225 }
1226 `,
1227                                 },
1228                         }),
1229                         offset: "/go/src/main/0.go:#54", to: "y", // var x
1230                         want: map[string]string{
1231                                 "/go/src/main/0.go": `package main
1232
1233 func main() {
1234         var unused, y int
1235         print(y)
1236 }
1237 `,
1238                         },
1239                 },
1240         } {
1241                 if test.ctxt != nil {
1242                         ctxt = test.ctxt
1243                 }
1244
1245                 got := make(map[string]string)
1246                 writeFile = func(filename string, content []byte) error {
1247                         got[filepath.ToSlash(filename)] = string(content)
1248                         return nil
1249                 }
1250
1251                 err := Main(ctxt, test.offset, test.from, test.to)
1252                 var prefix string
1253                 if test.offset == "" {
1254                         prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to)
1255                 } else {
1256                         prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to)
1257                 }
1258                 if err != nil {
1259                         t.Errorf("%s: unexpected error: %s", prefix, err)
1260                         continue
1261                 }
1262
1263                 for file, wantContent := range test.want {
1264                         gotContent, ok := got[file]
1265                         delete(got, file)
1266                         if !ok {
1267                                 t.Errorf("%s: file %s not rewritten", prefix, file)
1268                                 continue
1269                         }
1270                         if gotContent != wantContent {
1271                                 t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
1272                                         "want <<<%s>>>", prefix, file, gotContent, wantContent)
1273                         }
1274                 }
1275                 // got should now be empty
1276                 for file := range got {
1277                         t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
1278                 }
1279         }
1280 }
1281
1282 func TestDiff(t *testing.T) {
1283         switch runtime.GOOS {
1284         case "windows":
1285                 if os.Getenv("GO_BUILDER_NAME") != "" {
1286                         if _, err := exec.LookPath(DiffCmd); err != nil {
1287                                 t.Skipf("diff tool non-existent for %s on builders", runtime.GOOS)
1288                         }
1289                 }
1290         case "plan9":
1291                 t.Skipf("plan9 diff tool doesn't support -u flag")
1292         }
1293         testenv.NeedsTool(t, DiffCmd)
1294         testenv.NeedsTool(t, "go") // to locate the package to be renamed
1295
1296         defer func() {
1297                 Diff = false
1298                 stdout = os.Stdout
1299         }()
1300         Diff = true
1301         stdout = new(bytes.Buffer)
1302
1303         // Set up a fake GOPATH in a temporary directory,
1304         // and ensure we're in GOPATH mode.
1305         tmpdir, err := ioutil.TempDir("", "TestDiff")
1306         if err != nil {
1307                 t.Fatal(err)
1308         }
1309         defer os.RemoveAll(tmpdir)
1310         buildCtx := build.Default
1311         buildCtx.GOPATH = tmpdir
1312
1313         pkgDir := filepath.Join(tmpdir, "src", "example.com", "rename")
1314         if err := os.MkdirAll(pkgDir, 0777); err != nil {
1315                 t.Fatal(err)
1316         }
1317
1318         prevWD, err := os.Getwd()
1319         if err != nil {
1320                 t.Fatal(err)
1321         }
1322         defer os.Chdir(prevWD)
1323
1324         if err := os.Chdir(pkgDir); err != nil {
1325                 t.Fatal(err)
1326         }
1327
1328         const modFile = `module example.com/rename
1329
1330 go 1.15
1331 `
1332         if err := ioutil.WriteFile(filepath.Join(pkgDir, "go.mod"), []byte(modFile), 0644); err != nil {
1333                 t.Fatal(err)
1334         }
1335
1336         const goFile = `package rename
1337
1338 func justHereForTestingDiff() {
1339         justHereForTestingDiff()
1340 }
1341 `
1342         if err := ioutil.WriteFile(filepath.Join(pkgDir, "rename_test.go"), []byte(goFile), 0644); err != nil {
1343                 t.Fatal(err)
1344         }
1345
1346         if err := Main(&buildCtx, "", `"example.com/rename".justHereForTestingDiff`, "Foo"); err != nil {
1347                 t.Fatal(err)
1348         }
1349
1350         // NB: there are tabs in the string literal!
1351         if !strings.Contains(stdout.(fmt.Stringer).String(), `
1352 -func justHereForTestingDiff() {
1353 -       justHereForTestingDiff()
1354 +func Foo() {
1355 +       Foo()
1356  }
1357 `) {
1358                 t.Errorf("unexpected diff:\n<<%s>>", stdout)
1359         }
1360 }
1361
1362 // ---------------------------------------------------------------------
1363
1364 // Simplifying wrapper around buildutil.FakeContext for packages whose
1365 // filenames are sequentially numbered (%d.go).  pkgs maps a package
1366 // import path to its list of file contents.
1367 func fakeContext(pkgs map[string][]string) *build.Context {
1368         pkgs2 := make(map[string]map[string]string)
1369         for path, files := range pkgs {
1370                 filemap := make(map[string]string)
1371                 for i, contents := range files {
1372                         filemap[fmt.Sprintf("%d.go", i)] = contents
1373                 }
1374                 pkgs2[path] = filemap
1375         }
1376         return buildutil.FakeContext(pkgs2)
1377 }
1378
1379 // helper for single-file main packages with no imports.
1380 func main(content string) *build.Context {
1381         return fakeContext(map[string][]string{"main": {content}})
1382 }