refactor/rename: fix crash when renaming anonymous struct field that's a qualified reference
(or a pointer, or both). + test Fixes bug 8924 LGTM=sameer R=dominik.honnef, sameer CC=<dominik.honnef, golang-codereviews https://golang.org/cl/158920043
This commit is contained in:
parent
ab43333964
commit
fb44a24d4c
|
@ -293,10 +293,21 @@ func (r *renamer) checkStructField(from *types.Var) {
|
||||||
// method) to its declaring struct (or interface), so we must
|
// method) to its declaring struct (or interface), so we must
|
||||||
// ascend the AST.
|
// ascend the AST.
|
||||||
info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
|
info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
|
||||||
// path is [Ident Field FieldList StructType ... File]. Can't fail.
|
// path matches this pattern:
|
||||||
|
// [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File]
|
||||||
|
|
||||||
|
// Ascend to FieldList.
|
||||||
|
var i int
|
||||||
|
for {
|
||||||
|
if _, ok := path[i].(*ast.FieldList); ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
tStruct := path[i].(*ast.StructType)
|
||||||
|
i++
|
||||||
// Ascend past parens (unlikely).
|
// Ascend past parens (unlikely).
|
||||||
i := 4
|
|
||||||
for {
|
for {
|
||||||
_, ok := path[i].(*ast.ParenExpr)
|
_, ok := path[i].(*ast.ParenExpr)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -320,7 +331,7 @@ func (r *renamer) checkStructField(from *types.Var) {
|
||||||
} else {
|
} else {
|
||||||
// This struct is not a named type.
|
// This struct is not a named type.
|
||||||
// We need only check for direct (non-promoted) field/field conflicts.
|
// We need only check for direct (non-promoted) field/field conflicts.
|
||||||
T := info.Types[path[3].(*ast.StructType)].Type.Underlying().(*types.Struct)
|
T := info.Types[tStruct].Type.Underlying().(*types.Struct)
|
||||||
for i := 0; i < T.NumFields(); i++ {
|
for i := 0; i < T.NumFields(); i++ {
|
||||||
if prev := T.Field(i); prev.Name() == r.to {
|
if prev := T.Field(i); prev.Name() == r.to {
|
||||||
r.errorf(from.Pos(), "renaming this field %q to %q",
|
r.errorf(from.Pos(), "renaming this field %q to %q",
|
||||||
|
|
|
@ -648,6 +648,33 @@ func f(z interface{}) {
|
||||||
}
|
}
|
||||||
`},
|
`},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Renaming of embedded field that is a qualified reference.
|
||||||
|
// (Regression test for bug 8924.)
|
||||||
|
{
|
||||||
|
ctxt: fakeContext(map[string][]string{
|
||||||
|
"foo": {`package foo; type T int`},
|
||||||
|
"main": {`package main
|
||||||
|
|
||||||
|
import "foo"
|
||||||
|
|
||||||
|
type _ struct{ *foo.T }
|
||||||
|
`},
|
||||||
|
}),
|
||||||
|
offset: "/go/src/main/0.go:#48", to: "U", // the "T" in *foo.T
|
||||||
|
want: map[string]string{
|
||||||
|
"/go/src/foo/0.go": `package foo
|
||||||
|
|
||||||
|
type U int
|
||||||
|
`,
|
||||||
|
"/go/src/main/0.go": `package main
|
||||||
|
|
||||||
|
import "foo"
|
||||||
|
|
||||||
|
type _ struct{ *foo.U }
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
if test.ctxt != nil {
|
if test.ctxt != nil {
|
||||||
ctxt = test.ctxt
|
ctxt = test.ctxt
|
||||||
|
|
Loading…
Reference in New Issue