mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
refactor/rename: perform renaming in doc comments
Attempt to update doc comments when renaming an identifier. This reduces the amount of manual steps that need to be taken when using gorename. All occurrences of the old identifier are updated in the doc. The update is done using a regex to ensure that we replace whole word matches only. Fixes golang/go#17994 Change-Id: I4265021b5b34cf7d70bf43ad6ceee74ec132f185 Reviewed-on: https://go-review.googlesource.com/33452 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
955e2aeb12
commit
cbfb669053
@ -25,6 +25,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -163,7 +164,7 @@ type renamer struct {
|
||||
iprog *loader.Program
|
||||
objsToUpdate map[types.Object]bool
|
||||
hadConflicts bool
|
||||
to string
|
||||
from, to string
|
||||
satisfyConstraints map[satisfy.Constraint]bool
|
||||
packages map[*types.Package]*loader.PackageInfo // subset of iprog.AllPackages to inspect
|
||||
msets typeutil.MethodSetCache
|
||||
@ -314,6 +315,7 @@ func Main(ctxt *build.Context, offsetFlag, fromFlag, to string) error {
|
||||
r := renamer{
|
||||
iprog: iprog,
|
||||
objsToUpdate: make(map[types.Object]bool),
|
||||
from: spec.fromName,
|
||||
to: to,
|
||||
packages: make(map[*types.Package]*loader.PackageInfo),
|
||||
}
|
||||
@ -454,6 +456,8 @@ func (r *renamer) update() error {
|
||||
// token.File captures this distinction; filename does not.
|
||||
var nidents int
|
||||
var filesToUpdate = make(map[*token.File]bool)
|
||||
|
||||
docRegexp := regexp.MustCompile(`\b` + r.from + `\b`)
|
||||
for _, info := range r.packages {
|
||||
// Mutate the ASTs and note the filenames.
|
||||
for id, obj := range info.Defs {
|
||||
@ -461,8 +465,15 @@ func (r *renamer) update() error {
|
||||
nidents++
|
||||
id.Name = r.to
|
||||
filesToUpdate[r.iprog.Fset.File(id.Pos())] = true
|
||||
// Perform the rename in doc comments too.
|
||||
if doc := r.docComment(id); doc != nil {
|
||||
for _, comment := range doc.List {
|
||||
comment.Text = docRegexp.ReplaceAllString(comment.Text, r.to)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for id, obj := range info.Uses {
|
||||
if r.objsToUpdate[obj] {
|
||||
nidents++
|
||||
@ -513,6 +524,35 @@ func (r *renamer) update() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// docComment returns the doc for an identifier.
|
||||
func (r *renamer) docComment(id *ast.Ident) *ast.CommentGroup {
|
||||
_, nodes, _ := r.iprog.PathEnclosingInterval(id.Pos(), id.End())
|
||||
for _, node := range nodes {
|
||||
switch decl := node.(type) {
|
||||
case *ast.FuncDecl:
|
||||
return decl.Doc
|
||||
case *ast.Field:
|
||||
return decl.Doc
|
||||
case *ast.GenDecl:
|
||||
return decl.Doc
|
||||
// For {Type,Value}Spec, if the doc on the spec is absent,
|
||||
// search for the enclosing GenDecl
|
||||
case *ast.TypeSpec:
|
||||
if decl.Doc != nil {
|
||||
return decl.Doc
|
||||
}
|
||||
case *ast.ValueSpec:
|
||||
if decl.Doc != nil {
|
||||
return decl.Doc
|
||||
}
|
||||
case *ast.Ident:
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func plural(n int) string {
|
||||
if n != 1 {
|
||||
return "s"
|
||||
|
@ -521,6 +521,138 @@ var _ foo.U
|
||||
"/go/src/foo/0.go": `package foo
|
||||
|
||||
type U int
|
||||
`,
|
||||
},
|
||||
},
|
||||
// Rename package-level func plus doc
|
||||
{
|
||||
ctxt: main(`package main
|
||||
|
||||
// Foo is a no-op.
|
||||
// Calling Foo does nothing.
|
||||
func Foo() {
|
||||
}
|
||||
`),
|
||||
from: "main.Foo", to: "FooBar",
|
||||
want: map[string]string{
|
||||
"/go/src/main/0.go": `package main
|
||||
|
||||
// FooBar is a no-op.
|
||||
// Calling FooBar does nothing.
|
||||
func FooBar() {
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
// Rename method plus doc
|
||||
{
|
||||
ctxt: main(`package main
|
||||
|
||||
type Foo struct{}
|
||||
|
||||
// Bar does nothing.
|
||||
func (Foo) Bar() {
|
||||
}
|
||||
`),
|
||||
from: "main.Foo.Bar", to: "Baz",
|
||||
want: map[string]string{
|
||||
"/go/src/main/0.go": `package main
|
||||
|
||||
type Foo struct{}
|
||||
|
||||
// Baz does nothing.
|
||||
func (Foo) Baz() {
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
// Rename type spec plus doc
|
||||
{
|
||||
ctxt: main(`package main
|
||||
|
||||
type (
|
||||
// Test but not Testing.
|
||||
Test struct{}
|
||||
)
|
||||
`),
|
||||
from: "main.Test", to: "Type",
|
||||
want: map[string]string{
|
||||
"/go/src/main/0.go": `package main
|
||||
|
||||
type (
|
||||
// Type but not Testing.
|
||||
Type struct{}
|
||||
)
|
||||
`,
|
||||
},
|
||||
},
|
||||
// Rename type in gen decl plus doc
|
||||
{
|
||||
ctxt: main(`package main
|
||||
|
||||
// T is a test type.
|
||||
type T struct{}
|
||||
`),
|
||||
from: "main.T", to: "Type",
|
||||
want: map[string]string{
|
||||
"/go/src/main/0.go": `package main
|
||||
|
||||
// Type is a test type.
|
||||
type Type struct{}
|
||||
`,
|
||||
},
|
||||
},
|
||||
// Rename value spec with doc
|
||||
{
|
||||
ctxt: main(`package main
|
||||
|
||||
const (
|
||||
// C is the speed of light.
|
||||
C = 2.998e8
|
||||
)
|
||||
`),
|
||||
from: "main.C", to: "Lightspeed",
|
||||
want: map[string]string{
|
||||
"/go/src/main/0.go": `package main
|
||||
|
||||
const (
|
||||
// Lightspeed is the speed of light.
|
||||
Lightspeed = 2.998e8
|
||||
)
|
||||
`,
|
||||
},
|
||||
},
|
||||
// Rename value inside gen decl with doc
|
||||
{
|
||||
ctxt: main(`package main
|
||||
|
||||
var out *string
|
||||
`),
|
||||
from: "main.out", to: "discard",
|
||||
want: map[string]string{
|
||||
"/go/src/main/0.go": `package main
|
||||
|
||||
var discard *string
|
||||
`,
|
||||
},
|
||||
},
|
||||
// Rename field plus doc
|
||||
{
|
||||
ctxt: main(`package main
|
||||
|
||||
type Struct struct {
|
||||
// Field is a struct field.
|
||||
Field string
|
||||
}
|
||||
`),
|
||||
from: "main.Struct.Field", to: "Foo",
|
||||
want: map[string]string{
|
||||
"/go/src/main/0.go": `package main
|
||||
|
||||
type Struct struct {
|
||||
// Foo is a struct field.
|
||||
Foo string
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user