internal/lsp: update doc comments on rename

Replace doc comment text for the declaration of an identifier with the
new name.

This implementation is taken from golang.org/x/tools/refactor/rename.

Change-Id: Id1b80fad456646a46c8ae2caa4e8febf05aaf798
Reviewed-on: https://go-review.googlesource.com/c/tools/+/183261
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Suzy Mueller 2019-06-20 15:24:17 -04:00
parent 8ea4f8e3e5
commit 70d37148ca
2 changed files with 67 additions and 11 deletions

View File

@ -19,6 +19,7 @@ type ReferenceInfo struct {
Range span.Range Range span.Range
ident *ast.Ident ident *ast.Ident
obj types.Object obj types.Object
isDeclaration bool
} }
// References returns a list of references for a given identifier within a package. // References returns a list of references for a given identifier within a package.
@ -47,6 +48,7 @@ func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, erro
Name: i.decl.obj.Name(), Name: i.decl.obj.Name(),
Range: i.decl.rng, Range: i.decl.rng,
obj: i.decl.obj, obj: i.decl.obj,
isDeclaration: true,
}) })
} }
@ -59,6 +61,7 @@ func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, erro
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()), Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()),
ident: ident, ident: ident,
obj: obj, obj: obj,
isDeclaration: true,
}) })
} }

View File

@ -7,8 +7,10 @@ package source
import ( import (
"context" "context"
"fmt" "fmt"
"go/ast"
"go/token" "go/token"
"go/types" "go/types"
"regexp"
"golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/span" "golang.org/x/tools/internal/span"
@ -89,6 +91,7 @@ func Rename(ctx context.Context, view View, f GoFile, pos token.Pos, newName str
func (r *renamer) update(ctx context.Context, view View) (map[span.URI][]TextEdit, error) { func (r *renamer) update(ctx context.Context, view View) (map[span.URI][]TextEdit, error) {
result := make(map[span.URI][]TextEdit) result := make(map[span.URI][]TextEdit)
docRegexp := regexp.MustCompile(`\b` + r.from + `\b`)
for _, ref := range r.refs { for _, ref := range r.refs {
refSpan, err := ref.Range.Span() refSpan, err := ref.Range.Span()
if err != nil { if err != nil {
@ -100,7 +103,57 @@ func (r *renamer) update(ctx context.Context, view View) (map[span.URI][]TextEdi
NewText: r.to, NewText: r.to,
} }
result[refSpan.URI()] = append(result[refSpan.URI()], edit) result[refSpan.URI()] = append(result[refSpan.URI()], edit)
if ref.isDeclaration {
// Perform the rename in doc comments too (declared in the original package)
if doc := r.docComment(r.pkg, ref.ident); doc != nil {
for _, comment := range doc.List {
for _, locs := range docRegexp.FindAllStringIndex(comment.Text, -1) {
rng := span.NewRange(r.fset, comment.Pos()+token.Pos(locs[0]), comment.Pos()+token.Pos(locs[1]))
spn, err := rng.Span()
if err != nil {
return nil, err
}
result[refSpan.URI()] = append(result[refSpan.URI()], TextEdit{
Span: spn,
NewText: r.to,
})
}
comment.Text = docRegexp.ReplaceAllString(comment.Text, r.to)
}
}
}
} }
return result, nil return result, nil
} }
// docComment returns the doc for an identifier.
func (r *renamer) docComment(pkg Package, id *ast.Ident) *ast.CommentGroup {
_, nodes, _ := pathEnclosingInterval(r.fset, pkg, 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
}