golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/refactor/rename/rename_test.go (about)

     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  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"regexp"
    16  	"runtime"
    17  	"strings"
    18  	"testing"
    19  
    20  	"golang.org/x/tools/go/buildutil"
    21  	"golang.org/x/tools/internal/aliases"
    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  		alias            bool              // requires materialized aliases
   472  	}{
   473  		// Elimination of renaming import.
   474  		{
   475  			ctxt: fakeContext(map[string][]string{
   476  				"foo": {`package foo; type T int`},
   477  				"main": {`package main
   478  
   479  import foo2 "foo"
   480  
   481  var _ foo2.T
   482  `},
   483  			}),
   484  			from: "main::foo2", to: "foo",
   485  			want: map[string]string{
   486  				"/go/src/main/0.go": `package main
   487  
   488  import "foo"
   489  
   490  var _ foo.T
   491  `,
   492  			},
   493  		},
   494  		// Introduction of renaming import.
   495  		{
   496  			ctxt: fakeContext(map[string][]string{
   497  				"foo": {`package foo; type T int`},
   498  				"main": {`package main
   499  
   500  import "foo"
   501  
   502  var _ foo.T
   503  `},
   504  			}),
   505  			offset: "/go/src/main/0.go:#36", to: "foo2", // the "foo" in foo.T
   506  			want: map[string]string{
   507  				"/go/src/main/0.go": `package main
   508  
   509  import foo2 "foo"
   510  
   511  var _ foo2.T
   512  `,
   513  			},
   514  		},
   515  		// Renaming of package-level member.
   516  		{
   517  			from: "foo.T", to: "U",
   518  			want: map[string]string{
   519  				"/go/src/main/0.go": `package main
   520  
   521  import "foo"
   522  
   523  var _ foo.U
   524  `,
   525  				"/go/src/foo/0.go": `package foo
   526  
   527  type U int
   528  `,
   529  			},
   530  		},
   531  		// Rename package-level func plus doc
   532  		{
   533  			ctxt: main(`package main
   534  
   535  // Foo is a no-op.
   536  // Calling Foo does nothing.
   537  func Foo() {
   538  }
   539  `),
   540  			from: "main.Foo", to: "FooBar",
   541  			want: map[string]string{
   542  				"/go/src/main/0.go": `package main
   543  
   544  // FooBar is a no-op.
   545  // Calling FooBar does nothing.
   546  func FooBar() {
   547  }
   548  `,
   549  			},
   550  		},
   551  		// Rename method plus doc
   552  		{
   553  			ctxt: main(`package main
   554  
   555  type Foo struct{}
   556  
   557  // Bar does nothing.
   558  func (Foo) Bar() {
   559  }
   560  `),
   561  			from: "main.Foo.Bar", to: "Baz",
   562  			want: map[string]string{
   563  				"/go/src/main/0.go": `package main
   564  
   565  type Foo struct{}
   566  
   567  // Baz does nothing.
   568  func (Foo) Baz() {
   569  }
   570  `,
   571  			},
   572  		},
   573  		// Rename type spec plus doc
   574  		{
   575  			ctxt: main(`package main
   576  
   577  type (
   578  	// Test but not Testing.
   579  	Test struct{}
   580  )
   581  `),
   582  			from: "main.Test", to: "Type",
   583  			want: map[string]string{
   584  				"/go/src/main/0.go": `package main
   585  
   586  type (
   587  	// Type but not Testing.
   588  	Type struct{}
   589  )
   590  `,
   591  			},
   592  		},
   593  		// Rename type in gen decl plus doc
   594  		{
   595  			ctxt: main(`package main
   596  
   597  // T is a test type.
   598  type T struct{}
   599  `),
   600  			from: "main.T", to: "Type",
   601  			want: map[string]string{
   602  				"/go/src/main/0.go": `package main
   603  
   604  // Type is a test type.
   605  type Type struct{}
   606  `,
   607  			},
   608  		},
   609  		// Rename value spec with doc
   610  		{
   611  			ctxt: main(`package main
   612  
   613  const (
   614  	// C is the speed of light.
   615  	C = 2.998e8
   616  )
   617  `),
   618  			from: "main.C", to: "Lightspeed",
   619  			want: map[string]string{
   620  				"/go/src/main/0.go": `package main
   621  
   622  const (
   623  	// Lightspeed is the speed of light.
   624  	Lightspeed = 2.998e8
   625  )
   626  `,
   627  			},
   628  		},
   629  		// Rename value inside gen decl with doc
   630  		{
   631  			ctxt: main(`package main
   632  
   633  var out *string
   634  `),
   635  			from: "main.out", to: "discard",
   636  			want: map[string]string{
   637  				"/go/src/main/0.go": `package main
   638  
   639  var discard *string
   640  `,
   641  			},
   642  		},
   643  		// Rename field plus doc
   644  		{
   645  			ctxt: main(`package main
   646  
   647  type Struct struct {
   648  	// Field is a struct field.
   649  	Field string
   650  }
   651  `),
   652  			from: "main.Struct.Field", to: "Foo",
   653  			want: map[string]string{
   654  				"/go/src/main/0.go": `package main
   655  
   656  type Struct struct {
   657  	// Foo is a struct field.
   658  	Foo string
   659  }
   660  `,
   661  			},
   662  		},
   663  		// Label renamings.
   664  		{
   665  			ctxt: main(`package main
   666  func f() {
   667  loop:
   668  	loop := 0
   669  	go func() {
   670  	loop:
   671  		goto loop
   672  	}()
   673  	loop++
   674  	goto loop
   675  }
   676  `),
   677  			offset: "/go/src/main/0.go:#25", to: "loop2", // def of outer label "loop"
   678  			want: map[string]string{
   679  				"/go/src/main/0.go": `package main
   680  
   681  func f() {
   682  loop2:
   683  	loop := 0
   684  	go func() {
   685  	loop:
   686  		goto loop
   687  	}()
   688  	loop++
   689  	goto loop2
   690  }
   691  `,
   692  			},
   693  		},
   694  		{
   695  			offset: "/go/src/main/0.go:#70", to: "loop2", // ref to inner label "loop"
   696  			want: map[string]string{
   697  				"/go/src/main/0.go": `package main
   698  
   699  func f() {
   700  loop:
   701  	loop := 0
   702  	go func() {
   703  	loop2:
   704  		goto loop2
   705  	}()
   706  	loop++
   707  	goto loop
   708  }
   709  `,
   710  			},
   711  		},
   712  		// Renaming of type used as embedded field.
   713  		{
   714  			ctxt: main(`package main
   715  
   716  type T int
   717  type U struct { T }
   718  
   719  var _ = U{}.T
   720  `),
   721  			from: "main.T", to: "T2",
   722  			want: map[string]string{
   723  				"/go/src/main/0.go": `package main
   724  
   725  type T2 int
   726  type U struct{ T2 }
   727  
   728  var _ = U{}.T2
   729  `,
   730  			},
   731  		},
   732  		// Renaming of embedded field.
   733  		{
   734  			ctxt: main(`package main
   735  
   736  type T int
   737  type U struct { T }
   738  
   739  var _ = U{}.T
   740  `),
   741  			offset: "/go/src/main/0.go:#58", to: "T2", // T in "U{}.T"
   742  			want: map[string]string{
   743  				"/go/src/main/0.go": `package main
   744  
   745  type T2 int
   746  type U struct{ T2 }
   747  
   748  var _ = U{}.T2
   749  `,
   750  			},
   751  		},
   752  		// Renaming of pointer embedded field.
   753  		{
   754  			ctxt: main(`package main
   755  
   756  type T int
   757  type U struct { *T }
   758  
   759  var _ = U{}.T
   760  `),
   761  			offset: "/go/src/main/0.go:#59", to: "T2", // T in "U{}.T"
   762  			want: map[string]string{
   763  				"/go/src/main/0.go": `package main
   764  
   765  type T2 int
   766  type U struct{ *T2 }
   767  
   768  var _ = U{}.T2
   769  `,
   770  			},
   771  		},
   772  		// Renaming of embedded field alias.
   773  		{
   774  			alias: true,
   775  			ctxt: main(`package main
   776  
   777  type T int
   778  type A = T
   779  type U struct{ A }
   780  
   781  var _ = U{}.A
   782  var a A
   783  `),
   784  			offset: "/go/src/main/0.go:#68", to: "A2", // A in "U{}.A"
   785  			want: map[string]string{
   786  				"/go/src/main/0.go": `package main
   787  
   788  type T int
   789  type A2 = T
   790  type U struct{ A2 }
   791  
   792  var _ = U{}.A2
   793  var a A2
   794  `,
   795  			},
   796  		},
   797  		// Renaming of embedded field pointer to alias.
   798  		{
   799  			alias: true,
   800  			ctxt: main(`package main
   801  
   802  type T int
   803  type A = T
   804  type U struct{ *A }
   805  
   806  var _ = U{}.A
   807  var a A
   808  `),
   809  			offset: "/go/src/main/0.go:#69", to: "A2", // A in "U{}.A"
   810  			want: map[string]string{
   811  				"/go/src/main/0.go": `package main
   812  
   813  type T int
   814  type A2 = T
   815  type U struct{ *A2 }
   816  
   817  var _ = U{}.A2
   818  var a A2
   819  `,
   820  			},
   821  		},
   822  		// Renaming of alias
   823  		{
   824  			ctxt: main(`package main
   825  
   826  type A = int
   827  
   828  func _() A {
   829  	return A(0)
   830  }
   831  `),
   832  			offset: "/go/src/main/0.go:#49", to: "A2", // A in "A(0)"
   833  			want: map[string]string{
   834  				"/go/src/main/0.go": `package main
   835  
   836  type A2 = int
   837  
   838  func _() A2 {
   839  	return A2(0)
   840  }
   841  `,
   842  			},
   843  		},
   844  
   845  		// Lexical scope tests.
   846  		{
   847  			ctxt: main(`package main
   848  
   849  var y int
   850  
   851  func f() {
   852  	print(y)
   853  	y := ""
   854  	print(y)
   855  }
   856  `),
   857  			from: "main.y", to: "x",
   858  			want: map[string]string{
   859  				"/go/src/main/0.go": `package main
   860  
   861  var x int
   862  
   863  func f() {
   864  	print(x)
   865  	y := ""
   866  	print(y)
   867  }
   868  `,
   869  			},
   870  		},
   871  		{
   872  			from: "main.f::y", to: "x",
   873  			want: map[string]string{
   874  				"/go/src/main/0.go": `package main
   875  
   876  var y int
   877  
   878  func f() {
   879  	print(y)
   880  	x := ""
   881  	print(x)
   882  }
   883  `,
   884  			},
   885  		},
   886  		// Renaming of typeswitch vars (a corner case).
   887  		{
   888  			ctxt: main(`package main
   889  
   890  func f(z interface{}) {
   891  	switch y := z.(type) {
   892  	case int:
   893  		print(y)
   894  	default:
   895  		print(y)
   896  	}
   897  }
   898  `),
   899  			offset: "/go/src/main/0.go:#46", to: "x", // def of y
   900  			want: map[string]string{
   901  				"/go/src/main/0.go": `package main
   902  
   903  func f(z interface{}) {
   904  	switch x := z.(type) {
   905  	case int:
   906  		print(x)
   907  	default:
   908  		print(x)
   909  	}
   910  }
   911  `},
   912  		},
   913  		{
   914  			offset: "/go/src/main/0.go:#81", to: "x", // ref of y in case int
   915  			want: map[string]string{
   916  				"/go/src/main/0.go": `package main
   917  
   918  func f(z interface{}) {
   919  	switch x := z.(type) {
   920  	case int:
   921  		print(x)
   922  	default:
   923  		print(x)
   924  	}
   925  }
   926  `},
   927  		},
   928  		{
   929  			offset: "/go/src/main/0.go:#102", to: "x", // ref of y in default case
   930  			want: map[string]string{
   931  				"/go/src/main/0.go": `package main
   932  
   933  func f(z interface{}) {
   934  	switch x := z.(type) {
   935  	case int:
   936  		print(x)
   937  	default:
   938  		print(x)
   939  	}
   940  }
   941  `},
   942  		},
   943  
   944  		// Renaming of embedded field that is a qualified reference.
   945  		// (Regression test for bug 8924.)
   946  		{
   947  			ctxt: fakeContext(map[string][]string{
   948  				"foo": {`package foo; type T int`},
   949  				"main": {`package main
   950  
   951  import "foo"
   952  
   953  type _ struct{ *foo.T }
   954  `},
   955  			}),
   956  			offset: "/go/src/main/0.go:#48", to: "U", // the "T" in *foo.T
   957  			want: map[string]string{
   958  				"/go/src/foo/0.go": `package foo
   959  
   960  type U int
   961  `,
   962  				"/go/src/main/0.go": `package main
   963  
   964  import "foo"
   965  
   966  type _ struct{ *foo.U }
   967  `,
   968  			},
   969  		},
   970  
   971  		// Renaming of embedded field that is a qualified reference with the '-from' flag.
   972  		// (Regression test for bug 12038.)
   973  		{
   974  			ctxt: fakeContext(map[string][]string{
   975  				"foo": {`package foo; type T int`},
   976  				"main": {`package main
   977  
   978  import "foo"
   979  
   980  type V struct{ *foo.T }
   981  `},
   982  			}),
   983  			from: "(main.V).T", to: "U", // the "T" in *foo.T
   984  			want: map[string]string{
   985  				"/go/src/foo/0.go": `package foo
   986  
   987  type U int
   988  `,
   989  				"/go/src/main/0.go": `package main
   990  
   991  import "foo"
   992  
   993  type V struct{ *foo.U }
   994  `,
   995  			},
   996  		},
   997  		{
   998  			ctxt: fakeContext(map[string][]string{
   999  				"foo": {`package foo; type T int`},
  1000  				"main": {`package main
  1001  
  1002  import "foo"
  1003  
  1004  type V struct{ foo.T }
  1005  `},
  1006  			}),
  1007  			from: "(main.V).T", to: "U", // the "T" in *foo.T
  1008  			want: map[string]string{
  1009  				"/go/src/foo/0.go": `package foo
  1010  
  1011  type U int
  1012  `,
  1013  				"/go/src/main/0.go": `package main
  1014  
  1015  import "foo"
  1016  
  1017  type V struct{ foo.U }
  1018  `,
  1019  			},
  1020  		},
  1021  
  1022  		// Interface method renaming.
  1023  		{
  1024  			ctxt: fakeContext(map[string][]string{
  1025  				"main": {`
  1026  package main
  1027  type I interface {
  1028  	f()
  1029  }
  1030  type J interface { f(); g() }
  1031  type A int
  1032  func (A) f()
  1033  type B int
  1034  func (B) f()
  1035  func (B) g()
  1036  type C int
  1037  func (C) f()
  1038  func (C) g()
  1039  var _, _ I = A(0), B(0)
  1040  var _, _ J = B(0), C(0)
  1041  `,
  1042  				},
  1043  			}),
  1044  			offset: "/go/src/main/0.go:#34", to: "F", // abstract method I.f
  1045  			want: map[string]string{
  1046  				"/go/src/main/0.go": `package main
  1047  
  1048  type I interface {
  1049  	F()
  1050  }
  1051  type J interface {
  1052  	F()
  1053  	g()
  1054  }
  1055  type A int
  1056  
  1057  func (A) F()
  1058  
  1059  type B int
  1060  
  1061  func (B) F()
  1062  func (B) g()
  1063  
  1064  type C int
  1065  
  1066  func (C) F()
  1067  func (C) g()
  1068  
  1069  var _, _ I = A(0), B(0)
  1070  var _, _ J = B(0), C(0)
  1071  `,
  1072  			},
  1073  		},
  1074  		{
  1075  			offset: "/go/src/main/0.go:#59", to: "F", // abstract method J.f
  1076  			want: map[string]string{
  1077  				"/go/src/main/0.go": `package main
  1078  
  1079  type I interface {
  1080  	F()
  1081  }
  1082  type J interface {
  1083  	F()
  1084  	g()
  1085  }
  1086  type A int
  1087  
  1088  func (A) F()
  1089  
  1090  type B int
  1091  
  1092  func (B) F()
  1093  func (B) g()
  1094  
  1095  type C int
  1096  
  1097  func (C) F()
  1098  func (C) g()
  1099  
  1100  var _, _ I = A(0), B(0)
  1101  var _, _ J = B(0), C(0)
  1102  `,
  1103  			},
  1104  		},
  1105  		{
  1106  			offset: "/go/src/main/0.go:#64", to: "G", // abstract method J.g
  1107  			want: map[string]string{
  1108  				"/go/src/main/0.go": `package main
  1109  
  1110  type I interface {
  1111  	f()
  1112  }
  1113  type J interface {
  1114  	f()
  1115  	G()
  1116  }
  1117  type A int
  1118  
  1119  func (A) f()
  1120  
  1121  type B int
  1122  
  1123  func (B) f()
  1124  func (B) G()
  1125  
  1126  type C int
  1127  
  1128  func (C) f()
  1129  func (C) G()
  1130  
  1131  var _, _ I = A(0), B(0)
  1132  var _, _ J = B(0), C(0)
  1133  `,
  1134  			},
  1135  		},
  1136  		// Indirect coupling of I.f to C.f from D->I assignment and anonymous field of D.
  1137  		{
  1138  			ctxt: fakeContext(map[string][]string{
  1139  				"main": {`
  1140  package main
  1141  type I interface {
  1142  	f()
  1143  }
  1144  type C int
  1145  func (C) f()
  1146  type D struct{C}
  1147  var _ I = D{}
  1148  `,
  1149  				},
  1150  			}),
  1151  			offset: "/go/src/main/0.go:#34", to: "F", // abstract method I.f
  1152  			want: map[string]string{
  1153  				"/go/src/main/0.go": `package main
  1154  
  1155  type I interface {
  1156  	F()
  1157  }
  1158  type C int
  1159  
  1160  func (C) F()
  1161  
  1162  type D struct{ C }
  1163  
  1164  var _ I = D{}
  1165  `,
  1166  			},
  1167  		},
  1168  		// Interface embedded in struct.  No conflict if C need not satisfy I.
  1169  		{
  1170  			ctxt: fakeContext(map[string][]string{
  1171  				"main": {`
  1172  package main
  1173  type I interface {
  1174  	f()
  1175  }
  1176  type C struct{I}
  1177  func (C) g() int
  1178  var _ int = C{}.g()
  1179  `,
  1180  				},
  1181  			}),
  1182  			offset: "/go/src/main/0.go:#34", to: "g", // abstract method I.f
  1183  			want: map[string]string{
  1184  				"/go/src/main/0.go": `package main
  1185  
  1186  type I interface {
  1187  	g()
  1188  }
  1189  type C struct{ I }
  1190  
  1191  func (C) g() int
  1192  
  1193  var _ int = C{}.g()
  1194  `,
  1195  			},
  1196  		},
  1197  		// A type assertion causes method coupling iff signatures match.
  1198  		{
  1199  			ctxt: fakeContext(map[string][]string{
  1200  				"main": {`package main
  1201  type I interface{
  1202  	f()
  1203  }
  1204  type J interface{
  1205  	f()
  1206  }
  1207  var _ = I(nil).(J)
  1208  `,
  1209  				},
  1210  			}),
  1211  			offset: "/go/src/main/0.go:#32", to: "g", // abstract method I.f
  1212  			want: map[string]string{
  1213  				"/go/src/main/0.go": `package main
  1214  
  1215  type I interface {
  1216  	g()
  1217  }
  1218  type J interface {
  1219  	g()
  1220  }
  1221  
  1222  var _ = I(nil).(J)
  1223  `,
  1224  			},
  1225  		},
  1226  		// Impossible type assertion: no method coupling.
  1227  		{
  1228  			ctxt: fakeContext(map[string][]string{
  1229  				"main": {`package main
  1230  type I interface{
  1231  	f()
  1232  }
  1233  type J interface{
  1234  	f()int
  1235  }
  1236  var _ = I(nil).(J)
  1237  `,
  1238  				},
  1239  			}),
  1240  			offset: "/go/src/main/0.go:#32", to: "g", // abstract method I.f
  1241  			want: map[string]string{
  1242  				"/go/src/main/0.go": `package main
  1243  
  1244  type I interface {
  1245  	g()
  1246  }
  1247  type J interface {
  1248  	f() int
  1249  }
  1250  
  1251  var _ = I(nil).(J)
  1252  `,
  1253  			},
  1254  		},
  1255  		// Impossible type assertion: no method coupling C.f<->J.f.
  1256  		{
  1257  			ctxt: fakeContext(map[string][]string{
  1258  				"main": {`package main
  1259  type I interface{
  1260  	f()
  1261  }
  1262  type C int
  1263  func (C) f()
  1264  type J interface{
  1265  	f()int
  1266  }
  1267  var _ = I(C(0)).(J)
  1268  `,
  1269  				},
  1270  			}),
  1271  			offset: "/go/src/main/0.go:#32", to: "g", // abstract method I.f
  1272  			want: map[string]string{
  1273  				"/go/src/main/0.go": `package main
  1274  
  1275  type I interface {
  1276  	g()
  1277  }
  1278  type C int
  1279  
  1280  func (C) g()
  1281  
  1282  type J interface {
  1283  	f() int
  1284  }
  1285  
  1286  var _ = I(C(0)).(J)
  1287  `,
  1288  			},
  1289  		},
  1290  		// Progress after "soft" type errors (Go issue 14596).
  1291  		{
  1292  			ctxt: fakeContext(map[string][]string{
  1293  				"main": {`package main
  1294  
  1295  func main() {
  1296  	var unused, x int
  1297  	print(x)
  1298  }
  1299  `,
  1300  				},
  1301  			}),
  1302  			offset: "/go/src/main/0.go:#54", to: "y", // var x
  1303  			want: map[string]string{
  1304  				"/go/src/main/0.go": `package main
  1305  
  1306  func main() {
  1307  	var unused, y int
  1308  	print(y)
  1309  }
  1310  `,
  1311  			},
  1312  		},
  1313  	} {
  1314  		if test.ctxt != nil {
  1315  			ctxt = test.ctxt
  1316  		}
  1317  
  1318  		got := make(map[string]string)
  1319  		writeFile = func(filename string, content []byte) error {
  1320  			got[filepath.ToSlash(filename)] = string(content)
  1321  			return nil
  1322  		}
  1323  
  1324  		// Skip tests that require aliases when not enables.
  1325  		// (No test requires _no_ aliases,
  1326  		// so there is no contrapositive case.)
  1327  		if test.alias && !aliases.Enabled() {
  1328  			t.Log("test requires aliases")
  1329  			continue
  1330  		}
  1331  
  1332  		err := Main(ctxt, test.offset, test.from, test.to)
  1333  		var prefix string
  1334  		if test.offset == "" {
  1335  			prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to)
  1336  		} else {
  1337  			prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to)
  1338  		}
  1339  		if err != nil {
  1340  			t.Errorf("%s: unexpected error: %s", prefix, err)
  1341  			continue
  1342  		}
  1343  
  1344  		for file, wantContent := range test.want {
  1345  			gotContent, ok := got[file]
  1346  			delete(got, file)
  1347  			if !ok {
  1348  				t.Errorf("%s: file %s not rewritten", prefix, file)
  1349  				continue
  1350  			}
  1351  			if gotContent != wantContent {
  1352  				t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
  1353  					"want <<<%s>>>", prefix, file, gotContent, wantContent)
  1354  			}
  1355  		}
  1356  		// got should now be empty
  1357  		for file := range got {
  1358  			t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
  1359  		}
  1360  	}
  1361  }
  1362  
  1363  func TestDiff(t *testing.T) {
  1364  	switch runtime.GOOS {
  1365  	case "windows":
  1366  		if os.Getenv("GO_BUILDER_NAME") != "" {
  1367  			if _, err := exec.LookPath(DiffCmd); err != nil {
  1368  				t.Skipf("diff tool non-existent for %s on builders", runtime.GOOS)
  1369  			}
  1370  		}
  1371  	case "plan9":
  1372  		t.Skipf("plan9 diff tool doesn't support -u flag")
  1373  	}
  1374  	testenv.NeedsTool(t, DiffCmd)
  1375  	testenv.NeedsTool(t, "go") // to locate the package to be renamed
  1376  
  1377  	defer func() {
  1378  		Diff = false
  1379  		stdout = os.Stdout
  1380  	}()
  1381  	Diff = true
  1382  	stdout = new(bytes.Buffer)
  1383  
  1384  	// Set up a fake GOPATH in a temporary directory,
  1385  	// and ensure we're in GOPATH mode.
  1386  	tmpdir, err := os.MkdirTemp("", "TestDiff")
  1387  	if err != nil {
  1388  		t.Fatal(err)
  1389  	}
  1390  	defer os.RemoveAll(tmpdir)
  1391  	buildCtx := build.Default
  1392  	buildCtx.GOPATH = tmpdir
  1393  
  1394  	pkgDir := filepath.Join(tmpdir, "src", "example.com", "rename")
  1395  	if err := os.MkdirAll(pkgDir, 0777); err != nil {
  1396  		t.Fatal(err)
  1397  	}
  1398  
  1399  	prevWD, err := os.Getwd()
  1400  	if err != nil {
  1401  		t.Fatal(err)
  1402  	}
  1403  	defer os.Chdir(prevWD)
  1404  
  1405  	if err := os.Chdir(pkgDir); err != nil {
  1406  		t.Fatal(err)
  1407  	}
  1408  
  1409  	const modFile = `module example.com/rename
  1410  
  1411  go 1.15
  1412  `
  1413  	if err := os.WriteFile(filepath.Join(pkgDir, "go.mod"), []byte(modFile), 0644); err != nil {
  1414  		t.Fatal(err)
  1415  	}
  1416  
  1417  	const goFile = `package rename
  1418  
  1419  func justHereForTestingDiff() {
  1420  	justHereForTestingDiff()
  1421  }
  1422  `
  1423  	if err := os.WriteFile(filepath.Join(pkgDir, "rename_test.go"), []byte(goFile), 0644); err != nil {
  1424  		t.Fatal(err)
  1425  	}
  1426  
  1427  	if err := Main(&buildCtx, "", `"example.com/rename".justHereForTestingDiff`, "Foo"); err != nil {
  1428  		t.Fatal(err)
  1429  	}
  1430  
  1431  	// NB: there are tabs in the string literal!
  1432  	if !strings.Contains(stdout.(fmt.Stringer).String(), `
  1433  -func justHereForTestingDiff() {
  1434  -	justHereForTestingDiff()
  1435  +func Foo() {
  1436  +	Foo()
  1437   }
  1438  `) {
  1439  		t.Errorf("unexpected diff:\n<<%s>>", stdout)
  1440  	}
  1441  }
  1442  
  1443  // ---------------------------------------------------------------------
  1444  
  1445  // Simplifying wrapper around buildutil.FakeContext for packages whose
  1446  // filenames are sequentially numbered (%d.go).  pkgs maps a package
  1447  // import path to its list of file contents.
  1448  func fakeContext(pkgs map[string][]string) *build.Context {
  1449  	pkgs2 := make(map[string]map[string]string)
  1450  	for path, files := range pkgs {
  1451  		filemap := make(map[string]string)
  1452  		for i, contents := range files {
  1453  			filemap[fmt.Sprintf("%d.go", i)] = contents
  1454  		}
  1455  		pkgs2[path] = filemap
  1456  	}
  1457  	return buildutil.FakeContext(pkgs2)
  1458  }
  1459  
  1460  // helper for single-file main packages with no imports.
  1461  func main(content string) *build.Context {
  1462  	return fakeContext(map[string][]string{"main": {content}})
  1463  }