1
2
3
4
5 package rename
6
7
8
9 import (
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
20 func (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
26 func (r *renamer) check(from types.Object) {
27 if r.objsToUpdate[from] {
28 return
29 }
30 r.objsToUpdate[from] = true
31
32
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
52
53 func (r *renamer) checkInFileBlock(from *types.PkgName) {
54
55 if r.to == "init" {
56 r.errorf(from.Pos(), "%q is not a valid imported package name", r.to)
57 }
58
59
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
66 }
67
68
69 r.checkInLexicalScope(from, r.packages[from.Pkg()])
70
71
72 info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
73 if from.Imported().Name() == r.to {
74
75 path[1].(*ast.ImportSpec).Name = nil
76 } else {
77
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
86
87 func (r *renamer) checkInPackageBlock(from types.Object) {
88
89
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
105 if r.to == "init" {
106 kind := objectKind(from)
107 if kind == "func" {
108
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
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
134 }
135 }
136
137
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
147 func (r *renamer) checkInLocalScope(from types.Object) {
148 info := r.packages[from.Pkg()]
149
150
151
152
153
154
155
156
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
170 if isCaseVar {
171 _, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
172 path[0].(*ast.Ident).Name = r.to
173 }
174 }
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209 func (r *renamer) checkInLexicalScope(from types.Object, info *loader.PackageInfo) {
210 b := from.Parent()
211 if b != nil {
212 toBlock, to := b.LookupParent(r.to, from.Parent().End())
213 if toBlock == b {
214
215 r.errorf(from.Pos(), "renaming this %s %q to %q",
216 objectKind(from), from.Name(), r.to)
217 r.errorf(to.Pos(), "\tconflicts with %s in same block",
218 objectKind(to))
219 return
220 } else if toBlock != nil {
221
222
223
224 forEachLexicalRef(info, to, func(id *ast.Ident, block *types.Scope) bool {
225 _, obj := lexicalLookup(block, from.Name(), id.Pos())
226 if obj == from {
227
228 r.errorf(from.Pos(), "renaming this %s %q to %q",
229 objectKind(from), from.Name(), r.to)
230 r.errorf(id.Pos(), "\twould shadow this reference")
231 r.errorf(to.Pos(), "\tto the %s declared here",
232 objectKind(to))
233 return false
234 }
235 return true
236 })
237 }
238 }
239
240
241
242
243 forEachLexicalRef(info, from, func(id *ast.Ident, block *types.Scope) bool {
244
245
246 fromBlock, _ := lexicalLookup(block, from.Name(), id.Pos())
247
248
249 toBlock, to := lexicalLookup(block, r.to, id.Pos())
250 if to != nil {
251
252 if deeper(toBlock, fromBlock) {
253 r.errorf(from.Pos(), "renaming this %s %q to %q",
254 objectKind(from), from.Name(), r.to)
255 r.errorf(id.Pos(), "\twould cause this reference to become shadowed")
256 r.errorf(to.Pos(), "\tby this intervening %s definition",
257 objectKind(to))
258 return false
259 }
260 }
261 return true
262 })
263
264
265
266
267
268
269 if _, ok := from.(*types.TypeName); ok {
270 for id, obj := range info.Uses {
271 if obj == from {
272 if field := info.Defs[id]; field != nil {
273 r.check(field)
274 }
275 }
276 }
277 }
278 }
279
280
281
282
283 func lexicalLookup(block *types.Scope, name string, pos token.Pos) (*types.Scope, types.Object) {
284 for b := block; b != nil; b = b.Parent() {
285 obj := b.Lookup(name)
286
287
288
289
290 if obj != nil && (b == obj.Pkg().Scope() || obj.Pos() < pos) {
291 return b, obj
292 }
293 }
294 return nil, nil
295 }
296
297
298 func deeper(x, y *types.Scope) bool {
299 if x == y || x == nil {
300 return false
301 } else if y == nil {
302 return true
303 } else {
304 return deeper(x.Parent(), y.Parent())
305 }
306 }
307
308
309
310
311
312 func forEachLexicalRef(info *loader.PackageInfo, obj types.Object, fn func(id *ast.Ident, block *types.Scope) bool) bool {
313 ok := true
314 var stack []ast.Node
315
316 var visit func(n ast.Node) bool
317 visit = func(n ast.Node) bool {
318 if n == nil {
319 stack = stack[:len(stack)-1]
320 return false
321 }
322 if !ok {
323 return false
324 }
325
326 stack = append(stack, n)
327 switch n := n.(type) {
328 case *ast.Ident:
329 if info.Uses[n] == obj {
330 block := enclosingBlock(&info.Info, stack)
331 if !fn(n, block) {
332 ok = false
333 }
334 }
335 return visit(nil)
336
337 case *ast.SelectorExpr:
338
339 ast.Inspect(n.X, visit)
340 return visit(nil)
341
342 case *ast.CompositeLit:
343
344
345 tv := info.Types[n]
346 if _, ok := deref(tv.Type).Underlying().(*types.Struct); ok {
347 if n.Type != nil {
348 ast.Inspect(n.Type, visit)
349 }
350 for _, elt := range n.Elts {
351 if kv, ok := elt.(*ast.KeyValueExpr); ok {
352 ast.Inspect(kv.Value, visit)
353 } else {
354 ast.Inspect(elt, visit)
355 }
356 }
357 return visit(nil)
358 }
359 }
360 return true
361 }
362
363 for _, f := range info.Files {
364 ast.Inspect(f, visit)
365 if len(stack) != 0 {
366 panic(stack)
367 }
368 if !ok {
369 break
370 }
371 }
372 return ok
373 }
374
375
376
377
378 func enclosingBlock(info *types.Info, stack []ast.Node) *types.Scope {
379 for i := range stack {
380 n := stack[len(stack)-1-i]
381
382
383
384 switch f := n.(type) {
385 case *ast.FuncDecl:
386 n = f.Type
387 case *ast.FuncLit:
388 n = f.Type
389 }
390 if b := info.Scopes[n]; b != nil {
391 return b
392 }
393 }
394 panic("no Scope for *ast.File")
395 }
396
397 func (r *renamer) checkLabel(label *types.Label) {
398
399
400 if prev := label.Parent().Lookup(r.to); prev != nil {
401 r.errorf(label.Pos(), "renaming this label %q to %q", label.Name(), prev.Name())
402 r.errorf(prev.Pos(), "\twould conflict with this one")
403 }
404 }
405
406
407
408 func (r *renamer) checkStructField(from *types.Var) {
409
410
411
412
413
414
415 info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
416
417
418
419
420 var i int
421 for {
422 if _, ok := path[i].(*ast.FieldList); ok {
423 break
424 }
425 i++
426 }
427 i++
428 tStruct := path[i].(*ast.StructType)
429 i++
430
431 for {
432 _, ok := path[i].(*ast.ParenExpr)
433 if !ok {
434 break
435 }
436 i++
437 }
438 if spec, ok := path[i].(*ast.TypeSpec); ok {
439
440
441
442 named := info.Defs[spec.Name].Type()
443 prev, indices, _ := types.LookupFieldOrMethod(named, true, info.Pkg, r.to)
444 if len(indices) == 1 {
445 r.errorf(from.Pos(), "renaming this field %q to %q",
446 from.Name(), r.to)
447 r.errorf(prev.Pos(), "\twould conflict with this %s",
448 objectKind(prev))
449 return
450 }
451 } else {
452
453
454 T := info.Types[tStruct].Type.Underlying().(*types.Struct)
455 for i := 0; i < T.NumFields(); i++ {
456 if prev := T.Field(i); prev.Name() == r.to {
457 r.errorf(from.Pos(), "renaming this field %q to %q",
458 from.Name(), r.to)
459 r.errorf(prev.Pos(), "\twould conflict with this field")
460 return
461 }
462 }
463 }
464
465
466
467
468
469 if from.Anonymous() {
470 if named, ok := from.Type().(*types.Named); ok {
471 r.check(named.Obj())
472 } else if named, ok := deref(from.Type()).(*types.Named); ok {
473 r.check(named.Obj())
474 }
475 }
476
477
478 r.checkSelections(from)
479 }
480
481
482
483 func (r *renamer) checkSelections(from types.Object) {
484 for pkg, info := range r.packages {
485 if id := someUse(info, from); id != nil {
486 if !r.checkExport(id, pkg, from) {
487 return
488 }
489 }
490
491 for syntax, sel := range info.Selections {
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512 isAddressable := true
513
514 if sel.Obj() == from {
515 if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil {
516
517
518
519 delta := len(indices) - len(sel.Index())
520 if delta > 0 {
521 continue
522 }
523 r.selectionConflict(from, delta, syntax, obj)
524 return
525 }
526
527 } else if sel.Obj().Name() == r.to {
528 if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from {
529
530
531
532 delta := len(indices) - len(sel.Index())
533 if delta > 0 {
534 continue
535 }
536 r.selectionConflict(from, -delta, syntax, sel.Obj())
537 return
538 }
539 }
540 }
541 }
542 }
543
544 func (r *renamer) selectionConflict(from types.Object, delta int, syntax *ast.SelectorExpr, obj types.Object) {
545 r.errorf(from.Pos(), "renaming this %s %q to %q",
546 objectKind(from), from.Name(), r.to)
547
548 switch {
549 case delta < 0:
550
551 r.errorf(syntax.Sel.Pos(),
552 "\twould change the referent of this selection")
553 r.errorf(obj.Pos(), "\tof this %s", objectKind(obj))
554 case delta == 0:
555
556 r.errorf(syntax.Sel.Pos(),
557 "\twould make this reference ambiguous")
558 r.errorf(obj.Pos(), "\twith this %s", objectKind(obj))
559 case delta > 0:
560
561 r.errorf(syntax.Sel.Pos(),
562 "\twould shadow this selection")
563 r.errorf(obj.Pos(), "\tof the %s declared here",
564 objectKind(obj))
565 }
566 }
567
568
569
570
571
572
573
574
575
576
577
578 func (r *renamer) checkMethod(from *types.Func) {
579
580 if from.Pkg() == nil {
581 r.errorf(from.Pos(), "you cannot rename built-in method %s", from)
582 return
583 }
584
585
586
587
588
589
590
591
592
593 R := recv(from).Type()
594 if isInterface(R) {
595
596
597
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
607
608 for _, info := range r.packages {
609
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
630 for e, tv := range info.Types {
631 if e, ok := e.(*ast.InterfaceType); ok {
632 _ = e
633 _ = tv.Type.(*types.Interface)
634
635 }
636 }
637 }
638
639
640
641
642
643
644 for key := range r.satisfy() {
645
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
658
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
670
671
672
673
674
675
676
677
678
679
680
681
682
683 if !isInterface(key.RHS) {
684
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
692 }
693
694
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
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
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
715 }
716 }
717
718 if !r.changeMethods {
719
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
727 r.check(coupled)
728 }
729 } else {
730
731
732
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
743
744
745
746
747
748
749
750
751
752
753
754
755
756 for key := range r.satisfy() {
757
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
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
772
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
792 }
793
794
795 r.check(imeth)
796 }
797 }
798
799
800
801 r.checkSelections(from)
802 }
803
804 func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool {
805
806
807
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
820 func (r *renamer) satisfy() map[satisfy.Constraint]bool {
821 if r.satisfyConstraints == nil {
822
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
833
834
835 func recv(meth *types.Func) *types.Var {
836 return meth.Type().(*types.Signature).Recv()
837 }
838
839
840 func 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
850
851 func isInterface(T types.Type) bool { return types.IsInterface(T) }
852
853 func deref(typ types.Type) types.Type {
854 if p, _ := typ.(*types.Pointer); p != nil {
855 return p.Elem()
856 }
857 return typ
858 }
859
View as plain text