diff --git a/gopls/internal/regtest/misc/hover_test.go b/gopls/internal/regtest/misc/hover_test.go index 04dc740b89..4701b075ac 100644 --- a/gopls/internal/regtest/misc/hover_test.go +++ b/gopls/internal/regtest/misc/hover_test.go @@ -5,6 +5,7 @@ package misc import ( + "fmt" "strings" "testing" @@ -140,3 +141,83 @@ package main env.Editor.Hover(env.Ctx, "main.go", env.RegexpSearch("main.go", "foo")) }) } + +func TestHoverImport(t *testing.T) { + // For Go.13 and earlier versions, Go will try to download imported but missing packages. This behavior breaks the + // workspace as Go fails to download non-existent package "mod.com/lib4" + testenv.NeedsGo1Point(t, 14) + const packageDoc1 = "Package lib1 hover documentation" + const packageDoc2 = "Package lib2 hover documentation" + tests := []struct { + hoverPackage string + want string + }{ + { + "mod.com/lib1", + packageDoc1, + }, + { + "mod.com/lib2", + packageDoc2, + }, + { + "mod.com/lib3", + "", + }, + } + source := fmt.Sprintf(` +-- go.mod -- +module mod.com + +go 1.12 +-- lib1/a.go -- +// %s +package lib1 + +const C = 1 + +-- lib1/b.go -- +package lib1 + +const D = 1 + +-- lib2/a.go -- +// %s +package lib2 + +const E = 1 + +-- lib3/a.go -- +package lib3 + +const F = 1 + +-- main.go -- +package main + +import ( + "mod.com/lib1" + "mod.com/lib2" + "mod.com/lib3" + "mod.com/lib4" +) + +func main() { + println("Hello") +} + `, packageDoc1, packageDoc2) + Run(t, source, func(t *testing.T, env *Env) { + env.OpenFile("main.go") + for _, test := range tests { + got, _ := env.Hover("main.go", env.RegexpSearch("main.go", test.hoverPackage)) + if !strings.Contains(got.Value, test.want) { + t.Errorf("Hover: got:\n%q\nwant:\n%q", got.Value, test.want) + } + } + + got, _ := env.Hover("main.go", env.RegexpSearch("main.go", "mod.com/lib4")) + if got != nil { + t.Errorf("Hover: got:\n%q\nwant:\n%v", got.Value, nil) + } + }) +} diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go index 71a159c361..34c80aba0c 100644 --- a/internal/lsp/source/hover.go +++ b/internal/lsp/source/hover.go @@ -510,21 +510,25 @@ func FindHoverContext(ctx context.Context, s Snapshot, pkg Package, obj types.Ob } case *ast.ImportSpec: // Try to find the package documentation for an imported package. - if pkgName, ok := obj.(*types.PkgName); ok { - imp, err := pkg.GetImport(pkgName.Imported().Path()) - if err != nil { - return nil, err - } - // Assume that only one file will contain package documentation, - // so pick the first file that has a doc comment. - for _, file := range imp.GetSyntax() { - if file.Doc != nil { - info = &HoverContext{signatureSource: obj, Comment: file.Doc} - break + pkgPath, err := strconv.Unquote(node.Path.Value) + if err != nil { + return nil, err + } + imp, err := pkg.GetImport(pkgPath) + if err != nil { + return nil, err + } + // Assume that only one file will contain package documentation, + // so pick the first file that has a doc comment. + for _, file := range imp.GetSyntax() { + if file.Doc != nil { + info = &HoverContext{Comment: file.Doc} + if file.Name != nil { + info.signatureSource = "package " + file.Name.Name } + break } } - info = &HoverContext{signatureSource: node} case *ast.GenDecl: switch obj := obj.(type) { case *types.TypeName, *types.Var, *types.Const, *types.Func: