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