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