mirror of https://github.com/golang/go.git
internal/lsp: use LookupParent for finding scope
The lexicalLookup function is used to determine if a use of an object would be shadowed by a different definition after a rename. Switch to using LookupParent which is more careful about the positions of the identifiers. Fixes golang/go#47583 Change-Id: I3dbdf79e537ce637d1276ddbecb094db21f1c26d Reviewed-on: https://go-review.googlesource.com/c/tools/+/340551 Trust: Suzy Mueller <suzmue@golang.org> Run-TryBot: Suzy Mueller <suzmue@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
5f5a173a39
commit
f91c4a586e
|
|
@ -195,7 +195,7 @@ func (r *renamer) checkInLexicalScope(from types.Object, pkg Package) {
|
||||||
// The name r.to is defined in a superblock.
|
// The name r.to is defined in a superblock.
|
||||||
// Is that name referenced from within this block?
|
// Is that name referenced from within this block?
|
||||||
forEachLexicalRef(pkg, to, func(id *ast.Ident, block *types.Scope) bool {
|
forEachLexicalRef(pkg, to, func(id *ast.Ident, block *types.Scope) bool {
|
||||||
_, obj := lexicalLookup(block, from.Name(), id.Pos())
|
_, obj := block.LookupParent(from.Name(), id.Pos())
|
||||||
if obj == from {
|
if obj == from {
|
||||||
// super-block conflict
|
// super-block conflict
|
||||||
r.errorf(from.Pos(), "renaming this %s %q to %q",
|
r.errorf(from.Pos(), "renaming this %s %q to %q",
|
||||||
|
|
@ -215,10 +215,9 @@ func (r *renamer) checkInLexicalScope(from types.Object, pkg Package) {
|
||||||
forEachLexicalRef(pkg, from, func(id *ast.Ident, block *types.Scope) bool {
|
forEachLexicalRef(pkg, from, func(id *ast.Ident, block *types.Scope) bool {
|
||||||
// Find the block that defines the found reference.
|
// Find the block that defines the found reference.
|
||||||
// It may be an ancestor.
|
// It may be an ancestor.
|
||||||
fromBlock, _ := lexicalLookup(block, from.Name(), id.Pos())
|
fromBlock, _ := block.LookupParent(from.Name(), id.Pos())
|
||||||
|
|
||||||
// See what r.to would resolve to in the same scope.
|
// See what r.to would resolve to in the same scope.
|
||||||
toBlock, to := lexicalLookup(block, r.to, id.Pos())
|
toBlock, to := block.LookupParent(r.to, id.Pos())
|
||||||
if to != nil {
|
if to != nil {
|
||||||
// sub-block conflict
|
// sub-block conflict
|
||||||
if deeper(toBlock, fromBlock) {
|
if deeper(toBlock, fromBlock) {
|
||||||
|
|
@ -249,26 +248,6 @@ func (r *renamer) checkInLexicalScope(from types.Object, pkg Package) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// lexicalLookup is like (*types.Scope).LookupParent but respects the
|
|
||||||
// environment visible at pos. It assumes the relative position
|
|
||||||
// information is correct with each file.
|
|
||||||
func lexicalLookup(block *types.Scope, name string, pos token.Pos) (*types.Scope, types.Object) {
|
|
||||||
for b := block; b != nil; b = b.Parent() {
|
|
||||||
obj := b.Lookup(name)
|
|
||||||
// The scope of a package-level object is the entire package,
|
|
||||||
// so ignore pos in that case.
|
|
||||||
// No analogous clause is needed for file-level objects
|
|
||||||
// since no reference can appear before an import decl.
|
|
||||||
if obj == nil || obj.Pkg() == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if b == obj.Pkg().Scope() || obj.Pos() < pos {
|
|
||||||
return b, obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// deeper reports whether block x is lexically deeper than y.
|
// deeper reports whether block x is lexically deeper than y.
|
||||||
func deeper(x, y *types.Scope) bool {
|
func deeper(x, y *types.Scope) bool {
|
||||||
if x == y || x == nil {
|
if x == y || x == nil {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package shadow
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
a := true
|
||||||
|
b, c, _ := A(), B(), D() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d")
|
||||||
|
d := false
|
||||||
|
_, _, _, _ = a, b, c, d
|
||||||
|
}
|
||||||
|
|
||||||
|
func A() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func B() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func D() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
-- a-rename --
|
||||||
|
renaming this func "A" to "a" would cause this reference to become shadowed by this intervening var definition
|
||||||
|
-- b-rename --
|
||||||
|
package shadow
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
a := true
|
||||||
|
b, c, _ := A(), b(), D() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d")
|
||||||
|
d := false
|
||||||
|
_, _, _, _ = a, b, c, d
|
||||||
|
}
|
||||||
|
|
||||||
|
func A() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func b() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func D() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
-- c-rename --
|
||||||
|
renaming this var "b" to "c" conflicts with var in same block
|
||||||
|
-- d-rename --
|
||||||
|
package shadow
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
a := true
|
||||||
|
b, c, _ := A(), B(), d() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d")
|
||||||
|
d := false
|
||||||
|
_, _, _, _ = a, b, c, d
|
||||||
|
}
|
||||||
|
|
||||||
|
func A() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func B() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func d() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ DefinitionsCount = 95
|
||||||
TypeDefinitionsCount = 18
|
TypeDefinitionsCount = 18
|
||||||
HighlightsCount = 69
|
HighlightsCount = 69
|
||||||
ReferencesCount = 27
|
ReferencesCount = 27
|
||||||
RenamesCount = 37
|
RenamesCount = 41
|
||||||
PrepareRenamesCount = 7
|
PrepareRenamesCount = 7
|
||||||
SymbolsCount = 5
|
SymbolsCount = 5
|
||||||
WorkspaceSymbolsCount = 20
|
WorkspaceSymbolsCount = 20
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue