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
7// This file defines the safety checks for each kind of renaming.
8
9import (
10	"fmt"
11	"go/ast"
12	"go/token"
13	"go/types"
14
15	"golang.org/x/tools/go/loader"
16	"golang.org/x/tools/refactor/satisfy"
17)
18
19// errorf reports an error (e.g. conflict) and prevents file modification.
20func (r *renamer) errorf(pos token.Pos, format string, args ...interface{}) {
21	r.hadConflicts = true
22	reportError(r.iprog.Fset.Position(pos), fmt.Sprintf(format, args...))
23}
24
25// check performs safety checks of the renaming of the 'from' object to r.to.
26func (r *renamer) check(from types.Object) {
27	if r.objsToUpdate[from] {
28		return
29	}
30	r.objsToUpdate[from] = true
31
32	// NB: order of conditions is important.
33	if from_, ok := from.(*types.PkgName); ok {
34		r.checkInFileBlock(from_)
35	} else if from_, ok := from.(*types.Label); ok {
36		r.checkLabel(from_)
37	} else if isPackageLevel(from) {
38		r.checkInPackageBlock(from)
39	} else if v, ok := from.(*types.Var); ok && v.IsField() {
40		r.checkStructField(v)
41	} else if f, ok := from.(*types.Func); ok && recv(f) != nil {
42		r.checkMethod(f)
43	} else if isLocal(from) {
44		r.checkInLocalScope(from)
45	} else {
46		r.errorf(from.Pos(), "unexpected %s object %q (please report a bug)\n",
47			objectKind(from), from)
48	}
49}
50
51// checkInFileBlock performs safety checks for renames of objects in the file block,
52// i.e. imported package names.
53func (r *renamer) checkInFileBlock(from *types.PkgName) {
54	// Check import name is not "init".
55	if r.to == "init" {
56		r.errorf(from.Pos(), "%q is not a valid imported package name", r.to)
57	}
58
59	// Check for conflicts between file and package block.
60	if prev := from.Pkg().Scope().Lookup(r.to); prev != nil {
61		r.errorf(from.Pos(), "renaming this %s %q to %q would conflict",
62			objectKind(from), from.Name(), r.to)
63		r.errorf(prev.Pos(), "\twith this package member %s",
64			objectKind(prev))
65		return // since checkInPackageBlock would report redundant errors
66	}
67
68	// Check for conflicts in lexical scope.
69	r.checkInLexicalScope(from, r.packages[from.Pkg()])
70
71	// Finally, modify ImportSpec syntax to add or remove the Name as needed.
72	info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
73	if from.Imported().Name() == r.to {
74		// ImportSpec.Name not needed
75		path[1].(*ast.ImportSpec).Name = nil
76	} else {
77		// ImportSpec.Name needed
78		if spec := path[1].(*ast.ImportSpec); spec.Name == nil {
79			spec.Name = &ast.Ident{NamePos: spec.Path.Pos(), Name: r.to}
80			info.Defs[spec.Name] = from
81		}
82	}
83}
84
85// checkInPackageBlock performs safety checks for renames of
86// func/var/const/type objects in the package block.
87func (r *renamer) checkInPackageBlock(from types.Object) {
88	// Check that there are no references to the name from another
89	// package if the renaming would make it unexported.
90	if ast.IsExported(from.Name()) && !ast.IsExported(r.to) {
91		for pkg, info := range r.packages {
92			if pkg == from.Pkg() {
93				continue
94			}
95			if id := someUse(info, from); id != nil &&
96				!r.checkExport(id, pkg, from) {
97				break
98			}
99		}
100	}
101
102	info := r.packages[from.Pkg()]
103
104	// Check that in the package block, "init" is a function, and never referenced.
105	if r.to == "init" {
106		kind := objectKind(from)
107		if kind == "func" {
108			// Reject if intra-package references to it exist.
109			for id, obj := range info.Uses {
110				if obj == from {
111					r.errorf(from.Pos(),
112						"renaming this func %q to %q would make it a package initializer",
113						from.Name(), r.to)
114					r.errorf(id.Pos(), "\tbut references to it exist")
115					break
116				}
117			}
118		} else {
119			r.errorf(from.Pos(), "you cannot have a %s at package level named %q",
120				kind, r.to)
121		}
122	}
123
124	// Check for conflicts between package block and all file blocks.
125	for _, f := range info.Files {
126		fileScope := info.Info.Scopes[f]
127		b, prev := fileScope.LookupParent(r.to, token.NoPos)
128		if b == fileScope {
129			r.errorf(from.Pos(), "renaming this %s %q to %q would conflict",
130				objectKind(from), from.Name(), r.to)
131			r.errorf(prev.Pos(), "\twith this %s",
132				objectKind(prev))
133			return // since checkInPackageBlock would report redundant errors
134		}
135	}
136
137	// Check for conflicts in lexical scope.
138	if from.Exported() {
139		for _, info := range r.packages {
140			r.checkInLexicalScope(from, info)
141		}
142	} else {
143		r.checkInLexicalScope(from, info)
144	}
145}
146
147func (r *renamer) checkInLocalScope(from types.Object) {
148	info := r.packages[from.Pkg()]
149
150	// Is this object an implicit local var for a type switch?
151	// Each case has its own var, whose position is the decl of y,
152	// but Ident in that decl does not appear in the Uses map.
153	//
154	//   switch y := x.(type) {	 // Defs[Ident(y)] is undefined
155	//   case int:    print(y)       // Implicits[CaseClause(int)]    = Var(y_int)
156	//   case string: print(y)       // Implicits[CaseClause(string)] = Var(y_string)
157	//   }
158	//
159	var isCaseVar bool
160	for syntax, obj := range info.Implicits {
161		if _, ok := syntax.(*ast.CaseClause); ok && obj.Pos() == from.Pos() {
162			isCaseVar = true
163			r.check(obj)
164		}
165	}
166
167	r.checkInLexicalScope(from, info)
168
169	// Finally, if this was a type switch, change the variable y.
170	if isCaseVar {
171		_, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
172		path[0].(*ast.Ident).Name = r.to // path is [Ident AssignStmt TypeSwitchStmt...]
173	}
174}
175
176// checkInLexicalScope performs safety checks that a renaming does not
177// change the lexical reference structure of the specified package.
178//
179// For objects in lexical scope, there are three kinds of conflicts:
180// same-, sub-, and super-block conflicts.  We will illustrate all three
181// using this example:
182//
183//	var x int
184//	var z int
185//
186//	func f(y int) {
187//		print(x)
188//		print(y)
189//	}
190//
191// Renaming x to z encounters a SAME-BLOCK CONFLICT, because an object
192// with the new name already exists, defined in the same lexical block
193// as the old object.
194//
195// Renaming x to y encounters a SUB-BLOCK CONFLICT, because there exists
196// a reference to x from within (what would become) a hole in its scope.
197// The definition of y in an (inner) sub-block would cast a shadow in
198// the scope of the renamed variable.
199//
200// Renaming y to x encounters a SUPER-BLOCK CONFLICT.  This is the
201// converse situation: there is an existing definition of the new name
202// (x) in an (enclosing) super-block, and the renaming would create a
203// hole in its scope, within which there exist references to it.  The
204// new name casts a shadow in scope of the existing definition of x in
205// the super-block.
206//
207// Removing the old name (and all references to it) is always safe, and
208// requires no checks.
209//
210func (r *renamer) checkInLexicalScope(from types.Object, info *loader.PackageInfo) {
211	b := from.Parent() // the block defining the 'from' object
212	if b != nil {
213		toBlock, to := b.LookupParent(r.to, from.Parent().End())
214		if toBlock == b {
215			// same-block conflict
216			r.errorf(from.Pos(), "renaming this %s %q to %q",
217				objectKind(from), from.Name(), r.to)
218			r.errorf(to.Pos(), "\tconflicts with %s in same block",
219				objectKind(to))
220			return
221		} else if toBlock != nil {
222			// Check for super-block conflict.
223			// The name r.to is defined in a superblock.
224			// Is that name referenced from within this block?
225			forEachLexicalRef(info, to, func(id *ast.Ident, block *types.Scope) bool {
226				_, obj := lexicalLookup(block, from.Name(), id.Pos())
227				if obj == from {
228					// super-block conflict
229					r.errorf(from.Pos(), "renaming this %s %q to %q",
230						objectKind(from), from.Name(), r.to)
231					r.errorf(id.Pos(), "\twould shadow this reference")
232					r.errorf(to.Pos(), "\tto the %s declared here",
233						objectKind(to))
234					return false // stop
235				}
236				return true
237			})
238		}
239	}
240
241	// Check for sub-block conflict.
242	// Is there an intervening definition of r.to between
243	// the block defining 'from' and some reference to it?
244	forEachLexicalRef(info, from, func(id *ast.Ident, block *types.Scope) bool {
245		// Find the block that defines the found reference.
246		// It may be an ancestor.
247		fromBlock, _ := lexicalLookup(block, from.Name(), id.Pos())
248
249		// See what r.to would resolve to in the same scope.
250		toBlock, to := lexicalLookup(block, r.to, id.Pos())
251		if to != nil {
252			// sub-block conflict
253			if deeper(toBlock, fromBlock) {
254				r.errorf(from.Pos(), "renaming this %s %q to %q",
255					objectKind(from), from.Name(), r.to)
256				r.errorf(id.Pos(), "\twould cause this reference to become shadowed")
257				r.errorf(to.Pos(), "\tby this intervening %s definition",
258					objectKind(to))
259				return false // stop
260			}
261		}
262		return true
263	})
264
265	// Renaming a type that is used as an embedded field
266	// requires renaming the field too. e.g.
267	// 	type T int // if we rename this to U..
268	// 	var s struct {T}
269	// 	print(s.T) // ...this must change too
270	if _, ok := from.(*types.TypeName); ok {
271		for id, obj := range info.Uses {
272			if obj == from {
273				if field := info.Defs[id]; field != nil {
274					r.check(field)
275				}
276			}
277		}
278	}
279}
280
281// lexicalLookup is like (*types.Scope).LookupParent but respects the
282// environment visible at pos.  It assumes the relative position
283// information is correct with each file.
284func lexicalLookup(block *types.Scope, name string, pos token.Pos) (*types.Scope, types.Object) {
285	for b := block; b != nil; b = b.Parent() {
286		obj := b.Lookup(name)
287		// The scope of a package-level object is the entire package,
288		// so ignore pos in that case.
289		// No analogous clause is needed for file-level objects
290		// since no reference can appear before an import decl.
291		if obj != nil && (b == obj.Pkg().Scope() || obj.Pos() < pos) {
292			return b, obj
293		}
294	}
295	return nil, nil
296}
297
298// deeper reports whether block x is lexically deeper than y.
299func deeper(x, y *types.Scope) bool {
300	if x == y || x == nil {
301		return false
302	} else if y == nil {
303		return true
304	} else {
305		return deeper(x.Parent(), y.Parent())
306	}
307}
308
309// forEachLexicalRef calls fn(id, block) for each identifier id in package
310// info that is a reference to obj in lexical scope.  block is the
311// lexical block enclosing the reference.  If fn returns false the
312// iteration is terminated and findLexicalRefs returns false.
313func forEachLexicalRef(info *loader.PackageInfo, obj types.Object, fn func(id *ast.Ident, block *types.Scope) bool) bool {
314	ok := true
315	var stack []ast.Node
316
317	var visit func(n ast.Node) bool
318	visit = func(n ast.Node) bool {
319		if n == nil {
320			stack = stack[:len(stack)-1] // pop
321			return false
322		}
323		if !ok {
324			return false // bail out
325		}
326
327		stack = append(stack, n) // push
328		switch n := n.(type) {
329		case *ast.Ident:
330			if info.Uses[n] == obj {
331				block := enclosingBlock(&info.Info, stack)
332				if !fn(n, block) {
333					ok = false
334				}
335			}
336			return visit(nil) // pop stack
337
338		case *ast.SelectorExpr:
339			// don't visit n.Sel
340			ast.Inspect(n.X, visit)
341			return visit(nil) // pop stack, don't descend
342
343		case *ast.CompositeLit:
344			// Handle recursion ourselves for struct literals
345			// so we don't visit field identifiers.
346			tv := info.Types[n]
347			if _, ok := deref(tv.Type).Underlying().(*types.Struct); ok {
348				if n.Type != nil {
349					ast.Inspect(n.Type, visit)
350				}
351				for _, elt := range n.Elts {
352					if kv, ok := elt.(*ast.KeyValueExpr); ok {
353						ast.Inspect(kv.Value, visit)
354					} else {
355						ast.Inspect(elt, visit)
356					}
357				}
358				return visit(nil) // pop stack, don't descend
359			}
360		}
361		return true
362	}
363
364	for _, f := range info.Files {
365		ast.Inspect(f, visit)
366		if len(stack) != 0 {
367			panic(stack)
368		}
369		if !ok {
370			break
371		}
372	}
373	return ok
374}
375
376// enclosingBlock returns the innermost block enclosing the specified
377// AST node, specified in the form of a path from the root of the file,
378// [file...n].
379func enclosingBlock(info *types.Info, stack []ast.Node) *types.Scope {
380	for i := range stack {
381		n := stack[len(stack)-1-i]
382		// For some reason, go/types always associates a
383		// function's scope with its FuncType.
384		// TODO(adonovan): feature or a bug?
385		switch f := n.(type) {
386		case *ast.FuncDecl:
387			n = f.Type
388		case *ast.FuncLit:
389			n = f.Type
390		}
391		if b := info.Scopes[n]; b != nil {
392			return b
393		}
394	}
395	panic("no Scope for *ast.File")
396}
397
398func (r *renamer) checkLabel(label *types.Label) {
399	// Check there are no identical labels in the function's label block.
400	// (Label blocks don't nest, so this is easy.)
401	if prev := label.Parent().Lookup(r.to); prev != nil {
402		r.errorf(label.Pos(), "renaming this label %q to %q", label.Name(), prev.Name())
403		r.errorf(prev.Pos(), "\twould conflict with this one")
404	}
405}
406
407// checkStructField checks that the field renaming will not cause
408// conflicts at its declaration, or ambiguity or changes to any selection.
409func (r *renamer) checkStructField(from *types.Var) {
410	// Check that the struct declaration is free of field conflicts,
411	// and field/method conflicts.
412
413	// go/types offers no easy way to get from a field (or interface
414	// method) to its declaring struct (or interface), so we must
415	// ascend the AST.
416	info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
417	// path matches this pattern:
418	// [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File]
419
420	// Ascend to FieldList.
421	var i int
422	for {
423		if _, ok := path[i].(*ast.FieldList); ok {
424			break
425		}
426		i++
427	}
428	i++
429	tStruct := path[i].(*ast.StructType)
430	i++
431	// Ascend past parens (unlikely).
432	for {
433		_, ok := path[i].(*ast.ParenExpr)
434		if !ok {
435			break
436		}
437		i++
438	}
439	if spec, ok := path[i].(*ast.TypeSpec); ok {
440		// This struct is also a named type.
441		// We must check for direct (non-promoted) field/field
442		// and method/field conflicts.
443		named := info.Defs[spec.Name].Type()
444		prev, indices, _ := types.LookupFieldOrMethod(named, true, info.Pkg, r.to)
445		if len(indices) == 1 {
446			r.errorf(from.Pos(), "renaming this field %q to %q",
447				from.Name(), r.to)
448			r.errorf(prev.Pos(), "\twould conflict with this %s",
449				objectKind(prev))
450			return // skip checkSelections to avoid redundant errors
451		}
452	} else {
453		// This struct is not a named type.
454		// We need only check for direct (non-promoted) field/field conflicts.
455		T := info.Types[tStruct].Type.Underlying().(*types.Struct)
456		for i := 0; i < T.NumFields(); i++ {
457			if prev := T.Field(i); prev.Name() == r.to {
458				r.errorf(from.Pos(), "renaming this field %q to %q",
459					from.Name(), r.to)
460				r.errorf(prev.Pos(), "\twould conflict with this field")
461				return // skip checkSelections to avoid redundant errors
462			}
463		}
464	}
465
466	// Renaming an anonymous field requires renaming the type too. e.g.
467	// 	print(s.T)       // if we rename T to U,
468	// 	type T int       // this and
469	// 	var s struct {T} // this must change too.
470	if from.Anonymous() {
471		if named, ok := from.Type().(*types.Named); ok {
472			r.check(named.Obj())
473		} else if named, ok := deref(from.Type()).(*types.Named); ok {
474			r.check(named.Obj())
475		}
476	}
477
478	// Check integrity of existing (field and method) selections.
479	r.checkSelections(from)
480}
481
482// checkSelection checks that all uses and selections that resolve to
483// the specified object would continue to do so after the renaming.
484func (r *renamer) checkSelections(from types.Object) {
485	for pkg, info := range r.packages {
486		if id := someUse(info, from); id != nil {
487			if !r.checkExport(id, pkg, from) {
488				return
489			}
490		}
491
492		for syntax, sel := range info.Selections {
493			// There may be extant selections of only the old
494			// name or only the new name, so we must check both.
495			// (If neither, the renaming is sound.)
496			//
497			// In both cases, we wish to compare the lengths
498			// of the implicit field path (Selection.Index)
499			// to see if the renaming would change it.
500			//
501			// If a selection that resolves to 'from', when renamed,
502			// would yield a path of the same or shorter length,
503			// this indicates ambiguity or a changed referent,
504			// analogous to same- or sub-block lexical conflict.
505			//
506			// If a selection using the name 'to' would
507			// yield a path of the same or shorter length,
508			// this indicates ambiguity or shadowing,
509			// analogous to same- or super-block lexical conflict.
510
511			// TODO(adonovan): fix: derive from Types[syntax.X].Mode
512			// TODO(adonovan): test with pointer, value, addressable value.
513			isAddressable := true
514
515			if sel.Obj() == from {
516				if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil {
517					// Renaming this existing selection of
518					// 'from' may block access to an existing
519					// type member named 'to'.
520					delta := len(indices) - len(sel.Index())
521					if delta > 0 {
522						continue // no ambiguity
523					}
524					r.selectionConflict(from, delta, syntax, obj)
525					return
526				}
527
528			} else if sel.Obj().Name() == r.to {
529				if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from {
530					// Renaming 'from' may cause this existing
531					// selection of the name 'to' to change
532					// its meaning.
533					delta := len(indices) - len(sel.Index())
534					if delta > 0 {
535						continue //  no ambiguity
536					}
537					r.selectionConflict(from, -delta, syntax, sel.Obj())
538					return
539				}
540			}
541		}
542	}
543}
544
545func (r *renamer) selectionConflict(from types.Object, delta int, syntax *ast.SelectorExpr, obj types.Object) {
546	r.errorf(from.Pos(), "renaming this %s %q to %q",
547		objectKind(from), from.Name(), r.to)
548
549	switch {
550	case delta < 0:
551		// analogous to sub-block conflict
552		r.errorf(syntax.Sel.Pos(),
553			"\twould change the referent of this selection")
554		r.errorf(obj.Pos(), "\tof this %s", objectKind(obj))
555	case delta == 0:
556		// analogous to same-block conflict
557		r.errorf(syntax.Sel.Pos(),
558			"\twould make this reference ambiguous")
559		r.errorf(obj.Pos(), "\twith this %s", objectKind(obj))
560	case delta > 0:
561		// analogous to super-block conflict
562		r.errorf(syntax.Sel.Pos(),
563			"\twould shadow this selection")
564		r.errorf(obj.Pos(), "\tof the %s declared here",
565			objectKind(obj))
566	}
567}
568
569// checkMethod performs safety checks for renaming a method.
570// There are three hazards:
571// - declaration conflicts
572// - selection ambiguity/changes
573// - entailed renamings of assignable concrete/interface types.
574//   We reject renamings initiated at concrete methods if it would
575//   change the assignability relation.  For renamings of abstract
576//   methods, we rename all methods transitively coupled to it via
577//   assignability.
578func (r *renamer) checkMethod(from *types.Func) {
579	// e.g. error.Error
580	if from.Pkg() == nil {
581		r.errorf(from.Pos(), "you cannot rename built-in method %s", from)
582		return
583	}
584
585	// ASSIGNABILITY: We reject renamings of concrete methods that
586	// would break a 'satisfy' constraint; but renamings of abstract
587	// methods are allowed to proceed, and we rename affected
588	// concrete and abstract methods as necessary.  It is the
589	// initial method that determines the policy.
590
591	// Check for conflict at point of declaration.
592	// Check to ensure preservation of assignability requirements.
593	R := recv(from).Type()
594	if isInterface(R) {
595		// Abstract method
596
597		// declaration
598		prev, _, _ := types.LookupFieldOrMethod(R, false, from.Pkg(), r.to)
599		if prev != nil {
600			r.errorf(from.Pos(), "renaming this interface method %q to %q",
601				from.Name(), r.to)
602			r.errorf(prev.Pos(), "\twould conflict with this method")
603			return
604		}
605
606		// Check all interfaces that embed this one for
607		// declaration conflicts too.
608		for _, info := range r.packages {
609			// Start with named interface types (better errors)
610			for _, obj := range info.Defs {
611				if obj, ok := obj.(*types.TypeName); ok && isInterface(obj.Type()) {
612					f, _, _ := types.LookupFieldOrMethod(
613						obj.Type(), false, from.Pkg(), from.Name())
614					if f == nil {
615						continue
616					}
617					t, _, _ := types.LookupFieldOrMethod(
618						obj.Type(), false, from.Pkg(), r.to)
619					if t == nil {
620						continue
621					}
622					r.errorf(from.Pos(), "renaming this interface method %q to %q",
623						from.Name(), r.to)
624					r.errorf(t.Pos(), "\twould conflict with this method")
625					r.errorf(obj.Pos(), "\tin named interface type %q", obj.Name())
626				}
627			}
628
629			// Now look at all literal interface types (includes named ones again).
630			for e, tv := range info.Types {
631				if e, ok := e.(*ast.InterfaceType); ok {
632					_ = e
633					_ = tv.Type.(*types.Interface)
634					// TODO(adonovan): implement same check as above.
635				}
636			}
637		}
638
639		// assignability
640		//
641		// Find the set of concrete or abstract methods directly
642		// coupled to abstract method 'from' by some
643		// satisfy.Constraint, and rename them too.
644		for key := range r.satisfy() {
645			// key = (lhs, rhs) where lhs is always an interface.
646
647			lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name())
648			if lsel == nil {
649				continue
650			}
651			rmethods := r.msets.MethodSet(key.RHS)
652			rsel := rmethods.Lookup(from.Pkg(), from.Name())
653			if rsel == nil {
654				continue
655			}
656
657			// If both sides have a method of this name,
658			// and one of them is m, the other must be coupled.
659			var coupled *types.Func
660			switch from {
661			case lsel.Obj():
662				coupled = rsel.Obj().(*types.Func)
663			case rsel.Obj():
664				coupled = lsel.Obj().(*types.Func)
665			default:
666				continue
667			}
668
669			// We must treat concrete-to-interface
670			// constraints like an implicit selection C.f of
671			// each interface method I.f, and check that the
672			// renaming leaves the selection unchanged and
673			// unambiguous.
674			//
675			// Fun fact: the implicit selection of C.f
676			// 	type I interface{f()}
677			// 	type C struct{I}
678			// 	func (C) g()
679			//      var _ I = C{} // here
680			// yields abstract method I.f.  This can make error
681			// messages less than obvious.
682			//
683			if !isInterface(key.RHS) {
684				// The logic below was derived from checkSelections.
685
686				rtosel := rmethods.Lookup(from.Pkg(), r.to)
687				if rtosel != nil {
688					rto := rtosel.Obj().(*types.Func)
689					delta := len(rsel.Index()) - len(rtosel.Index())
690					if delta < 0 {
691						continue // no ambiguity
692					}
693
694					// TODO(adonovan): record the constraint's position.
695					keyPos := token.NoPos
696
697					r.errorf(from.Pos(), "renaming this method %q to %q",
698						from.Name(), r.to)
699					if delta == 0 {
700						// analogous to same-block conflict
701						r.errorf(keyPos, "\twould make the %s method of %s invoked via interface %s ambiguous",
702							r.to, key.RHS, key.LHS)
703						r.errorf(rto.Pos(), "\twith (%s).%s",
704							recv(rto).Type(), r.to)
705					} else {
706						// analogous to super-block conflict
707						r.errorf(keyPos, "\twould change the %s method of %s invoked via interface %s",
708							r.to, key.RHS, key.LHS)
709						r.errorf(coupled.Pos(), "\tfrom (%s).%s",
710							recv(coupled).Type(), r.to)
711						r.errorf(rto.Pos(), "\tto (%s).%s",
712							recv(rto).Type(), r.to)
713					}
714					return // one error is enough
715				}
716			}
717
718			if !r.changeMethods {
719				// This should be unreachable.
720				r.errorf(from.Pos(), "internal error: during renaming of abstract method %s", from)
721				r.errorf(coupled.Pos(), "\tchangedMethods=false, coupled method=%s", coupled)
722				r.errorf(from.Pos(), "\tPlease file a bug report")
723				return
724			}
725
726			// Rename the coupled method to preserve assignability.
727			r.check(coupled)
728		}
729	} else {
730		// Concrete method
731
732		// declaration
733		prev, indices, _ := types.LookupFieldOrMethod(R, true, from.Pkg(), r.to)
734		if prev != nil && len(indices) == 1 {
735			r.errorf(from.Pos(), "renaming this method %q to %q",
736				from.Name(), r.to)
737			r.errorf(prev.Pos(), "\twould conflict with this %s",
738				objectKind(prev))
739			return
740		}
741
742		// assignability
743		//
744		// Find the set of abstract methods coupled to concrete
745		// method 'from' by some satisfy.Constraint, and rename
746		// them too.
747		//
748		// Coupling may be indirect, e.g. I.f <-> C.f via type D.
749		//
750		// 	type I interface {f()}
751		//	type C int
752		//	type (C) f()
753		//	type D struct{C}
754		//	var _ I = D{}
755		//
756		for key := range r.satisfy() {
757			// key = (lhs, rhs) where lhs is always an interface.
758			if isInterface(key.RHS) {
759				continue
760			}
761			rsel := r.msets.MethodSet(key.RHS).Lookup(from.Pkg(), from.Name())
762			if rsel == nil || rsel.Obj() != from {
763				continue // rhs does not have the method
764			}
765			lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name())
766			if lsel == nil {
767				continue
768			}
769			imeth := lsel.Obj().(*types.Func)
770
771			// imeth is the abstract method (e.g. I.f)
772			// and key.RHS is the concrete coupling type (e.g. D).
773			if !r.changeMethods {
774				r.errorf(from.Pos(), "renaming this method %q to %q",
775					from.Name(), r.to)
776				var pos token.Pos
777				var iface string
778
779				I := recv(imeth).Type()
780				if named, ok := I.(*types.Named); ok {
781					pos = named.Obj().Pos()
782					iface = "interface " + named.Obj().Name()
783				} else {
784					pos = from.Pos()
785					iface = I.String()
786				}
787				r.errorf(pos, "\twould make %s no longer assignable to %s",
788					key.RHS, iface)
789				r.errorf(imeth.Pos(), "\t(rename %s.%s if you intend to change both types)",
790					I, from.Name())
791				return // one error is enough
792			}
793
794			// Rename the coupled interface method to preserve assignability.
795			r.check(imeth)
796		}
797	}
798
799	// Check integrity of existing (field and method) selections.
800	// We skip this if there were errors above, to avoid redundant errors.
801	r.checkSelections(from)
802}
803
804func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool {
805	// Reject cross-package references if r.to is unexported.
806	// (Such references may be qualified identifiers or field/method
807	// selections.)
808	if !ast.IsExported(r.to) && pkg != from.Pkg() {
809		r.errorf(from.Pos(),
810			"renaming this %s %q to %q would make it unexported",
811			objectKind(from), from.Name(), r.to)
812		r.errorf(id.Pos(), "\tbreaking references from packages such as %q",
813			pkg.Path())
814		return false
815	}
816	return true
817}
818
819// satisfy returns the set of interface satisfaction constraints.
820func (r *renamer) satisfy() map[satisfy.Constraint]bool {
821	if r.satisfyConstraints == nil {
822		// Compute on demand: it's expensive.
823		var f satisfy.Finder
824		for _, info := range r.packages {
825			f.Find(&info.Info, info.Files)
826		}
827		r.satisfyConstraints = f.Result
828	}
829	return r.satisfyConstraints
830}
831
832// -- helpers ----------------------------------------------------------
833
834// recv returns the method's receiver.
835func recv(meth *types.Func) *types.Var {
836	return meth.Type().(*types.Signature).Recv()
837}
838
839// someUse returns an arbitrary use of obj within info.
840func someUse(info *loader.PackageInfo, obj types.Object) *ast.Ident {
841	for id, o := range info.Uses {
842		if o == obj {
843			return id
844		}
845	}
846	return nil
847}
848
849// -- Plundered from golang.org/x/tools/go/ssa -----------------
850
851func isInterface(T types.Type) bool { return types.IsInterface(T) }
852
853func deref(typ types.Type) types.Type {
854	if p, _ := typ.(*types.Pointer); p != nil {
855		return p.Elem()
856	}
857	return typ
858}
859