internal/lsp: fix hover for implicit type switch variable declarations
There was a bug in the hover for type switch variables. For example:
var x interface{}
switch y := x.(type) {
case string:
case int:
}
Hovering over y would previously show "var y string", because y's object
would be mapped to the first types.Object in the type switch. Now we
show the hover for y as "var y interface{}", since it's not yet in the
cases.
Change-Id: Ia9bd0afc4ddbb9d33bbd0c78fa32ffa75836a326
Reviewed-on: https://go-review.googlesource.com/c/tools/+/244497
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go
index a3ddc89..e19dda1 100644
--- a/internal/lsp/source/hover.go
+++ b/internal/lsp/source/hover.go
@@ -96,7 +96,13 @@
}
h.Signature = b.String()
case types.Object:
- h.Signature = objectString(x, i.qf)
+ // If the variable is implicitly declared in a type switch, we need to
+ // manually generate its object string.
+ if v, ok := x.(*types.Var); ok && i.Declaration.typeSwitchImplicit {
+ h.Signature = fmt.Sprintf("var %s %s", v.Name(), types.TypeString(i.enclosing, i.qf))
+ } else {
+ h.Signature = objectString(x, i.qf)
+ }
}
if obj := i.Declaration.obj; obj != nil {
h.SingleLine = objectString(obj, i.qf)
diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go
index 2d49c1d..25ea2d0 100644
--- a/internal/lsp/source/identifier.go
+++ b/internal/lsp/source/identifier.go
@@ -43,6 +43,10 @@
MappedRange []mappedRange
node ast.Node
obj types.Object
+
+ // typeSwitchImplicit indicates that the declaration is in an implicit
+ // type switch.
+ typeSwitchImplicit bool
}
// Identifier returns identifier information for a position
@@ -152,9 +156,10 @@
result.Declaration.obj = pkg.GetTypesInfo().ObjectOf(result.ident)
if result.Declaration.obj == nil {
- // If there was no types.Object for the declaration, there might be an implicit local variable
- // declaration in a type switch.
+ // If there was no types.Object for the declaration, there might be an
+ // implicit local variable declaration in a type switch.
if objs := typeSwitchImplicits(pkg, path); len(objs) > 0 {
+ result.Declaration.typeSwitchImplicit = true
// There is no types.Object for the declaration of an implicit local variable,
// but all of the types.Objects associated with the usages of this variable can be
// used to connect it back to the declaration.
@@ -244,6 +249,15 @@
return t.Type()
}
}
+ case *ast.TypeSwitchStmt:
+ // The right-hand side of a type switch should only have one
+ // element, and we need to track its type in order to generate
+ // hover information for implicit type switch variables.
+ if assign, ok := n.Assign.(*ast.AssignStmt); ok && len(assign.Rhs) == 1 {
+ if rhs := assign.Rhs[0].(*ast.TypeAssertExpr); ok {
+ return pkg.GetTypesInfo().TypeOf(rhs.X)
+ }
+ }
}
}
return nil
@@ -269,12 +283,10 @@
if err != nil {
return nil, err
}
-
posToDecl, err := ph.PosToDecl(ctx)
if err != nil {
return nil, err
}
-
return posToDecl[obj.Pos()], nil
}
diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go
index b1bc10e..417e1e6 100644
--- a/internal/lsp/source/source_test.go
+++ b/internal/lsp/source/source_test.go
@@ -514,7 +514,7 @@
return []byte(hover), nil
}))
if hover != expectHover {
- t.Errorf("for %v got %q want %q", d.Src, hover, expectHover)
+ t.Errorf("hover for %s failed:\n%s", d.Src, tests.Diff(expectHover, hover))
}
}
if !d.OnlyHover {
diff --git a/internal/lsp/testdata/lsp/primarymod/godef/a/f.go b/internal/lsp/testdata/lsp/primarymod/godef/a/f.go
index d1b8c23..2d3eefc 100644
--- a/internal/lsp/testdata/lsp/primarymod/godef/a/f.go
+++ b/internal/lsp/testdata/lsp/primarymod/godef/a/f.go
@@ -5,11 +5,11 @@
func TypeStuff() { //@Stuff
var x string
- switch y := interface{}(x).(type) { //@mark(switchY, "y"),mark(switchStringY,"y"),godef("y", switchY)
- case int:
- fmt.Printf("%v", y) //@godef("y", switchY)
- case string:
- fmt.Printf("%v", y) //@godef("y", switchStringY)
+ switch y := interface{}(x).(type) { //@mark(switchY, "y"),godef("y", switchY)
+ case int: //@mark(intY, "int")
+ fmt.Printf("%v", y) //@hover("y", intY)
+ case string: //@mark(stringY, "string")
+ fmt.Printf("%v", y) //@hover("y", stringY)
}
}
diff --git a/internal/lsp/testdata/lsp/primarymod/godef/a/f.go.golden b/internal/lsp/testdata/lsp/primarymod/godef/a/f.go.golden
index 1a220e0..6c84b4d 100644
--- a/internal/lsp/testdata/lsp/primarymod/godef/a/f.go.golden
+++ b/internal/lsp/testdata/lsp/primarymod/godef/a/f.go.golden
@@ -1,32 +1,14 @@
--- switchStringY-definition --
-godef/a/f.go:8:9-10: defined here as ```go
-var y string
+-- intY-hover --
+```go
+var y int
```
--- switchStringY-definition-json --
-{
- "span": {
- "uri": "file://godef/a/f.go",
- "start": {
- "line": 8,
- "column": 9,
- "offset": 76
- },
- "end": {
- "line": 8,
- "column": 10,
- "offset": 77
- }
- },
- "description": "```go\nvar y string\n```"
-}
-
--- switchStringY-hover --
+-- stringY-hover --
```go
var y string
```
-- switchY-definition --
godef/a/f.go:8:9-10: defined here as ```go
-var y int
+var y interface{}
```
-- switchY-definition-json --
{
@@ -43,10 +25,10 @@
"offset": 77
}
},
- "description": "```go\nvar y int\n```"
+ "description": "```go\nvar y interface{}\n```"
}
-- switchY-hover --
```go
-var y int
+var y interface{}
```
diff --git a/internal/lsp/testdata/lsp/primarymod/godef/b/e.go b/internal/lsp/testdata/lsp/primarymod/godef/b/e.go
index dc8fe6e..92037ed 100644
--- a/internal/lsp/testdata/lsp/primarymod/godef/b/e.go
+++ b/internal/lsp/testdata/lsp/primarymod/godef/b/e.go
@@ -19,3 +19,13 @@
godef(bVar, Other)
godef(bFunc, Things)
*/
+
+func _() {
+ var x interface{} //@mark(eInterface, "interface{}")
+ switch x := x.(type) { //@hover("x", eInterface)
+ case string: //@mark(eString, "string")
+ fmt.Println(x) //@hover("x", eString)
+ case int: //@mark(eInt, "int")
+ fmt.Println(x) //@hover("x", eInt)
+ }
+}
diff --git a/internal/lsp/testdata/lsp/primarymod/godef/b/e.go.golden b/internal/lsp/testdata/lsp/primarymod/godef/b/e.go.golden
index f0bfe97..1e11a0f 100644
--- a/internal/lsp/testdata/lsp/primarymod/godef/b/e.go.golden
+++ b/internal/lsp/testdata/lsp/primarymod/godef/b/e.go.golden
@@ -130,3 +130,15 @@
```
[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#Things)
+-- eInt-hover --
+```go
+var x int
+```
+-- eInterface-hover --
+```go
+var x interface{}
+```
+-- eString-hover --
+```go
+var x string
+```
diff --git a/internal/lsp/testdata/lsp/summary.txt.golden b/internal/lsp/testdata/lsp/summary.txt.golden
index 2009987..4c64565 100644
--- a/internal/lsp/testdata/lsp/summary.txt.golden
+++ b/internal/lsp/testdata/lsp/summary.txt.golden
@@ -13,7 +13,7 @@
ImportCount = 8
SuggestedFixCount = 31
FunctionExtractionCount = 5
-DefinitionsCount = 53
+DefinitionsCount = 56
TypeDefinitionsCount = 2
HighlightsCount = 69
ReferencesCount = 11