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/internal/typeparams"
17 "golang.org/x/tools/internal/typesinternal"
18 "golang.org/x/tools/refactor/satisfy"
19 )
20
21
22 func (r *renamer) errorf(pos token.Pos, format string, args ...interface{}) {
23 r.hadConflicts = true
24 reportError(r.iprog.Fset.Position(pos), fmt.Sprintf(format, args...))
25 }
26
27
28 func (r *renamer) check(from types.Object) {
29 if r.objsToUpdate[from] {
30 return
31 }
32 r.objsToUpdate[from] = true
33
34
35 if from_, ok := from.(*types.PkgName); ok {
36 r.checkInFileBlock(from_)
37 } else if from_, ok := from.(*types.Label); ok {
38 r.checkLabel(from_)
39 } else if isPackageLevel(from) {
40 r.checkInPackageBlock(from)
41 } else if v, ok := from.(*types.Var); ok && v.IsField() {
42 r.checkStructField(v)
43 } else if f, ok := from.(*types.Func); ok && recv(f) != nil {
44 r.checkMethod(f)
45 } else if isLocal(from) {
46 r.checkInLocalScope(from)
47 } else {
48 r.errorf(from.Pos(), "unexpected %s object %q (please report a bug)\n",
49 objectKind(from), from)
50 }
51 }
52
53
54
55 func (r *renamer) checkInFileBlock(from *types.PkgName) {
56
57 if r.to == "init" {
58 r.errorf(from.Pos(), "%q is not a valid imported package name", r.to)
59 }
60
61
62 if prev := from.Pkg().Scope().Lookup(r.to); prev != nil {
63 r.errorf(from.Pos(), "renaming this %s %q to %q would conflict",
64 objectKind(from), from.Name(), r.to)
65 r.errorf(prev.Pos(), "\twith this package member %s",
66 objectKind(prev))
67 return
68 }
69
70
71 r.checkInLexicalScope(from, r.packages[from.Pkg()])
72
73
74 info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
75 if from.Imported().Name() == r.to {
76
77 path[1].(*ast.ImportSpec).Name = nil
78 } else {
79
80 if spec := path[1].(*ast.ImportSpec); spec.Name == nil {
81 spec.Name = &ast.Ident{NamePos: spec.Path.Pos(), Name: r.to}
82 info.Defs[spec.Name] = from
83 }
84 }
85 }
86
87
88
89 func (r *renamer) checkInPackageBlock(from types.Object) {
90
91
92 if ast.IsExported(from.Name()) && !ast.IsExported(r.to) {
93 for pkg, info := range r.packages {
94 if pkg == from.Pkg() {
95 continue
96 }
97 if id := someUse(info, from); id != nil &&
98 !r.checkExport(id, pkg, from) {
99 break
100 }
101 }
102 }
103
104 info := r.packages[from.Pkg()]
105
106
107 if r.to == "init" {
108 kind := objectKind(from)
109 if kind == "func" {
110
111 for id, obj := range info.Uses {
112 if obj == from {
113 r.errorf(from.Pos(),
114 "renaming this func %q to %q would make it a package initializer",
115 from.Name(), r.to)
116 r.errorf(id.Pos(), "\tbut references to it exist")
117 break
118 }
119 }
120 } else {
121 r.errorf(from.Pos(), "you cannot have a %s at package level named %q",
122 kind, r.to)
123 }
124 }
125
126
127 for _, f := range info.Files {
128 fileScope := info.Info.Scopes[f]
129 b, prev := fileScope.LookupParent(r.to, token.NoPos)
130 if b == fileScope {
131 r.errorf(from.Pos(), "renaming this %s %q to %q would conflict",
132 objectKind(from), from.Name(), r.to)
133 r.errorf(prev.Pos(), "\twith this %s",
134 objectKind(prev))
135 return
136 }
137 }
138
139
140 if from.Exported() {
141 for _, info := range r.packages {
142 r.checkInLexicalScope(from, info)
143 }
144 } else {
145 r.checkInLexicalScope(from, info)
146 }
147 }
148
149 func (r *renamer) checkInLocalScope(from types.Object) {
150 info := r.packages[from.Pkg()]
151
152
153
154
155
156
157
158
159
160
161 var isCaseVar bool
162 for syntax, obj := range info.Implicits {
163 if _, ok := syntax.(*ast.CaseClause); ok && obj.Pos() == from.Pos() {
164 isCaseVar = true
165 r.check(obj)
166 }
167 }
168
169 r.checkInLexicalScope(from, info)
170
171
172 if isCaseVar {
173 _, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
174 path[0].(*ast.Ident).Name = r.to
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
210
211 func (r *renamer) checkInLexicalScope(from types.Object, info *loader.PackageInfo) {
212 b := from.Parent()
213 if b != nil {
214 toBlock, to := b.LookupParent(r.to, from.Parent().End())
215 if toBlock == b {
216
217 r.errorf(from.Pos(), "renaming this %s %q to %q",
218 objectKind(from), from.Name(), r.to)
219 r.errorf(to.Pos(), "\tconflicts with %s in same block",
220 objectKind(to))
221 return
222 } else if toBlock != nil {
223
224
225
226 forEachLexicalRef(info, to, func(id *ast.Ident, block *types.Scope) bool {
227 _, obj := lexicalLookup(block, from.Name(), id.Pos())
228 if obj == from {
229
230 r.errorf(from.Pos(), "renaming this %s %q to %q",
231 objectKind(from), from.Name(), r.to)
232 r.errorf(id.Pos(), "\twould shadow this reference")
233 r.errorf(to.Pos(), "\tto the %s declared here",
234 objectKind(to))
235 return false
236 }
237 return true
238 })
239 }
240 }
241
242
243
244
245 forEachLexicalRef(info, from, func(id *ast.Ident, block *types.Scope) bool {
246
247
248 fromBlock, _ := lexicalLookup(block, from.Name(), id.Pos())
249
250
251 toBlock, to := lexicalLookup(block, r.to, id.Pos())
252 if to != nil {
253
254 if deeper(toBlock, fromBlock) {
255 r.errorf(from.Pos(), "renaming this %s %q to %q",
256 objectKind(from), from.Name(), r.to)
257 r.errorf(id.Pos(), "\twould cause this reference to become shadowed")
258 r.errorf(to.Pos(), "\tby this intervening %s definition",
259 objectKind(to))
260 return false
261 }
262 }
263 return true
264 })
265
266
267
268
269
270
271 if _, ok := from.(*types.TypeName); ok {
272 for id, obj := range info.Uses {
273 if obj == from {
274 if field := info.Defs[id]; field != nil {
275 r.check(field)
276 }
277 }
278 }
279 }
280 }
281
282
283
284
285 func lexicalLookup(block *types.Scope, name string, pos token.Pos) (*types.Scope, types.Object) {
286 for b := block; b != nil; b = b.Parent() {
287 obj := b.Lookup(name)
288
289
290
291
292 if obj != nil && (b == obj.Pkg().Scope() || obj.Pos() < pos) {
293 return b, obj
294 }
295 }
296 return nil, nil
297 }
298
299
300 func deeper(x, y *types.Scope) bool {
301 if x == y || x == nil {
302 return false
303 } else if y == nil {
304 return true
305 } else {
306 return deeper(x.Parent(), y.Parent())
307 }
308 }
309
310
311
312
313
314 func forEachLexicalRef(info *loader.PackageInfo, obj types.Object, fn func(id *ast.Ident, block *types.Scope) bool) bool {
315 ok := true
316 var stack []ast.Node
317
318 var visit func(n ast.Node) bool
319 visit = func(n ast.Node) bool {
320 if n == nil {
321 stack = stack[:len(stack)-1]
322 return false
323 }
324 if !ok {
325 return false
326 }
327
328 stack = append(stack, n)
329 switch n := n.(type) {
330 case *ast.Ident:
331 if info.Uses[n] == obj {
332 block := enclosingBlock(&info.Info, stack)
333 if !fn(n, block) {
334 ok = false
335 }
336 }
337 return visit(nil)
338
339 case *ast.SelectorExpr:
340
341 ast.Inspect(n.X, visit)
342 return visit(nil)
343
344 case *ast.CompositeLit:
345
346
347 tv := info.Types[n]
348 if is[*types.Struct](typeparams.CoreType(typeparams.Deref(tv.Type))) {
349 if n.Type != nil {
350 ast.Inspect(n.Type, visit)
351 }
352 for _, elt := range n.Elts {
353 if kv, ok := elt.(*ast.KeyValueExpr); ok {
354 ast.Inspect(kv.Value, visit)
355 } else {
356 ast.Inspect(elt, visit)
357 }
358 }
359 return visit(nil)
360 }
361 }
362 return true
363 }
364
365 for _, f := range info.Files {
366 ast.Inspect(f, visit)
367 if len(stack) != 0 {
368 panic(stack)
369 }
370 if !ok {
371 break
372 }
373 }
374 return ok
375 }
376
377
378
379
380 func enclosingBlock(info *types.Info, stack []ast.Node) *types.Scope {
381 for i := range stack {
382 n := stack[len(stack)-1-i]
383
384
385
386 switch f := n.(type) {
387 case *ast.FuncDecl:
388 n = f.Type
389 case *ast.FuncLit:
390 n = f.Type
391 }
392 if b := info.Scopes[n]; b != nil {
393 return b
394 }
395 }
396 panic("no Scope for *ast.File")
397 }
398
399 func (r *renamer) checkLabel(label *types.Label) {
400
401
402 if prev := label.Parent().Lookup(r.to); prev != nil {
403 r.errorf(label.Pos(), "renaming this label %q to %q", label.Name(), prev.Name())
404 r.errorf(prev.Pos(), "\twould conflict with this one")
405 }
406 }
407
408
409
410 func (r *renamer) checkStructField(from *types.Var) {
411
412
413
414
415
416
417 info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
418
419
420
421
422 var i int
423 for {
424 if _, ok := path[i].(*ast.FieldList); ok {
425 break
426 }
427 i++
428 }
429 i++
430 tStruct := path[i].(*ast.StructType)
431 i++
432
433 for {
434 _, ok := path[i].(*ast.ParenExpr)
435 if !ok {
436 break
437 }
438 i++
439 }
440 if spec, ok := path[i].(*ast.TypeSpec); ok && !spec.Assign.IsValid() {
441
442
443
444 named := info.Defs[spec.Name].Type()
445 prev, indices, _ := types.LookupFieldOrMethod(named, true, info.Pkg, r.to)
446 if len(indices) == 1 {
447 r.errorf(from.Pos(), "renaming this field %q to %q",
448 from.Name(), r.to)
449 r.errorf(prev.Pos(), "\twould conflict with this %s",
450 objectKind(prev))
451 return
452 }
453 } else {
454
455
456 T := info.Types[tStruct].Type.Underlying().(*types.Struct)
457 for i := 0; i < T.NumFields(); i++ {
458 if prev := T.Field(i); prev.Name() == r.to {
459 r.errorf(from.Pos(), "renaming this field %q to %q",
460 from.Name(), r.to)
461 r.errorf(prev.Pos(), "\twould conflict with this field")
462 return
463 }
464 }
465 }
466
467
468
469
470
471 if from.Anonymous() {
472
473 if t, ok := typesinternal.Unpointer(from.Type()).(hasTypeName); ok {
474 r.check(t.Obj())
475 }
476 }
477
478
479 r.checkSelections(from)
480 }
481
482
483 type hasTypeName interface{ Obj() *types.TypeName }
484
485
486
487 func (r *renamer) checkSelections(from types.Object) {
488 for pkg, info := range r.packages {
489 if id := someUse(info, from); id != nil {
490 if !r.checkExport(id, pkg, from) {
491 return
492 }
493 }
494
495 for syntax, sel := range info.Selections {
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516 isAddressable := true
517
518 if sel.Obj() == from {
519 if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil {
520
521
522
523 delta := len(indices) - len(sel.Index())
524 if delta > 0 {
525 continue
526 }
527 r.selectionConflict(from, delta, syntax, obj)
528 return
529 }
530
531 } else if sel.Obj().Name() == r.to {
532 if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from {
533
534
535
536 delta := len(indices) - len(sel.Index())
537 if delta > 0 {
538 continue
539 }
540 r.selectionConflict(from, -delta, syntax, sel.Obj())
541 return
542 }
543 }
544 }
545 }
546 }
547
548 func (r *renamer) selectionConflict(from types.Object, delta int, syntax *ast.SelectorExpr, obj types.Object) {
549 r.errorf(from.Pos(), "renaming this %s %q to %q",
550 objectKind(from), from.Name(), r.to)
551
552 switch {
553 case delta < 0:
554
555 r.errorf(syntax.Sel.Pos(),
556 "\twould change the referent of this selection")
557 r.errorf(obj.Pos(), "\tof this %s", objectKind(obj))
558 case delta == 0:
559
560 r.errorf(syntax.Sel.Pos(),
561 "\twould make this reference ambiguous")
562 r.errorf(obj.Pos(), "\twith this %s", objectKind(obj))
563 case delta > 0:
564
565 r.errorf(syntax.Sel.Pos(),
566 "\twould shadow this selection")
567 r.errorf(obj.Pos(), "\tof the %s declared here",
568 objectKind(obj))
569 }
570 }
571
572
573
574
575
576
577
578
579
580
581
582 func (r *renamer) checkMethod(from *types.Func) {
583
584 if from.Pkg() == nil {
585 r.errorf(from.Pos(), "you cannot rename built-in method %s", from)
586 return
587 }
588
589
590
591
592
593
594
595
596
597 R := recv(from).Type()
598 if types.IsInterface(R) {
599
600
601
602 prev, _, _ := types.LookupFieldOrMethod(R, false, from.Pkg(), r.to)
603 if prev != nil {
604 r.errorf(from.Pos(), "renaming this interface method %q to %q",
605 from.Name(), r.to)
606 r.errorf(prev.Pos(), "\twould conflict with this method")
607 return
608 }
609
610
611
612 for _, info := range r.packages {
613
614 for _, obj := range info.Defs {
615 if obj, ok := obj.(*types.TypeName); ok && types.IsInterface(obj.Type()) {
616 f, _, _ := types.LookupFieldOrMethod(
617 obj.Type(), false, from.Pkg(), from.Name())
618 if f == nil {
619 continue
620 }
621 t, _, _ := types.LookupFieldOrMethod(
622 obj.Type(), false, from.Pkg(), r.to)
623 if t == nil {
624 continue
625 }
626 r.errorf(from.Pos(), "renaming this interface method %q to %q",
627 from.Name(), r.to)
628 r.errorf(t.Pos(), "\twould conflict with this method")
629 r.errorf(obj.Pos(), "\tin named interface type %q", obj.Name())
630 }
631 }
632
633
634 for e, tv := range info.Types {
635 if e, ok := e.(*ast.InterfaceType); ok {
636 _ = e
637 _ = tv.Type.(*types.Interface)
638
639 }
640 }
641 }
642
643
644
645
646
647
648 for key := range r.satisfy() {
649
650
651 lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name())
652 if lsel == nil {
653 continue
654 }
655 rmethods := r.msets.MethodSet(key.RHS)
656 rsel := rmethods.Lookup(from.Pkg(), from.Name())
657 if rsel == nil {
658 continue
659 }
660
661
662
663 var coupled *types.Func
664 switch from {
665 case lsel.Obj():
666 coupled = rsel.Obj().(*types.Func)
667 case rsel.Obj():
668 coupled = lsel.Obj().(*types.Func)
669 default:
670 continue
671 }
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687 if !types.IsInterface(key.RHS) {
688
689
690 rtosel := rmethods.Lookup(from.Pkg(), r.to)
691 if rtosel != nil {
692 rto := rtosel.Obj().(*types.Func)
693 delta := len(rsel.Index()) - len(rtosel.Index())
694 if delta < 0 {
695 continue
696 }
697
698
699 keyPos := token.NoPos
700
701 r.errorf(from.Pos(), "renaming this method %q to %q",
702 from.Name(), r.to)
703 if delta == 0 {
704
705 r.errorf(keyPos, "\twould make the %s method of %s invoked via interface %s ambiguous",
706 r.to, key.RHS, key.LHS)
707 r.errorf(rto.Pos(), "\twith (%s).%s",
708 recv(rto).Type(), r.to)
709 } else {
710
711 r.errorf(keyPos, "\twould change the %s method of %s invoked via interface %s",
712 r.to, key.RHS, key.LHS)
713 r.errorf(coupled.Pos(), "\tfrom (%s).%s",
714 recv(coupled).Type(), r.to)
715 r.errorf(rto.Pos(), "\tto (%s).%s",
716 recv(rto).Type(), r.to)
717 }
718 return
719 }
720 }
721
722 if !r.changeMethods {
723
724 r.errorf(from.Pos(), "internal error: during renaming of abstract method %s", from)
725 r.errorf(coupled.Pos(), "\tchangedMethods=false, coupled method=%s", coupled)
726 r.errorf(from.Pos(), "\tPlease file a bug report")
727 return
728 }
729
730
731 r.check(coupled)
732 }
733 } else {
734
735
736
737 prev, indices, _ := types.LookupFieldOrMethod(R, true, from.Pkg(), r.to)
738 if prev != nil && len(indices) == 1 {
739 r.errorf(from.Pos(), "renaming this method %q to %q",
740 from.Name(), r.to)
741 r.errorf(prev.Pos(), "\twould conflict with this %s",
742 objectKind(prev))
743 return
744 }
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760 for key := range r.satisfy() {
761
762 if types.IsInterface(key.RHS) {
763 continue
764 }
765 rsel := r.msets.MethodSet(key.RHS).Lookup(from.Pkg(), from.Name())
766 if rsel == nil || rsel.Obj() != from {
767 continue
768 }
769 lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name())
770 if lsel == nil {
771 continue
772 }
773 imeth := lsel.Obj().(*types.Func)
774
775
776
777 if !r.changeMethods {
778 r.errorf(from.Pos(), "renaming this method %q to %q",
779 from.Name(), r.to)
780 var pos token.Pos
781 var iface string
782
783 I := recv(imeth).Type()
784 if named, ok := I.(hasTypeName); ok {
785 pos = named.Obj().Pos()
786 iface = "interface " + named.Obj().Name()
787 } else {
788 pos = from.Pos()
789 iface = I.String()
790 }
791 r.errorf(pos, "\twould make %s no longer assignable to %s",
792 key.RHS, iface)
793 r.errorf(imeth.Pos(), "\t(rename %s.%s if you intend to change both types)",
794 I, from.Name())
795 return
796 }
797
798
799 r.check(imeth)
800 }
801 }
802
803
804
805 r.checkSelections(from)
806 }
807
808 func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool {
809
810
811
812 if !ast.IsExported(r.to) && pkg != from.Pkg() {
813 r.errorf(from.Pos(),
814 "renaming this %s %q to %q would make it unexported",
815 objectKind(from), from.Name(), r.to)
816 r.errorf(id.Pos(), "\tbreaking references from packages such as %q",
817 pkg.Path())
818 return false
819 }
820 return true
821 }
822
823
824 func (r *renamer) satisfy() map[satisfy.Constraint]bool {
825 if r.satisfyConstraints == nil {
826
827 var f satisfy.Finder
828 for _, info := range r.packages {
829 f.Find(&info.Info, info.Files)
830 }
831 r.satisfyConstraints = f.Result
832 }
833 return r.satisfyConstraints
834 }
835
836
837
838
839 func recv(meth *types.Func) *types.Var {
840 return meth.Type().(*types.Signature).Recv()
841 }
842
843
844 func someUse(info *loader.PackageInfo, obj types.Object) *ast.Ident {
845 for id, o := range info.Uses {
846 if o == obj {
847 return id
848 }
849 }
850 return nil
851 }
852
View as plain text