Skip to content

Commit bf1b00e

Browse files
findleyrgopherbot
authored andcommitted
gopls/internal/golang: reproduce various edge cases of issue 69616
For some reason, I finally realized how the "impossible" edge cases of golang/go#69616 could occur: in one case, there are scenarios where the type checker doesn't actually type-check a compiled go file. In another, there is exactly one package with a Go file that isn't compiled: unsafe. These reproduced the two bug reports in golang/go#69616. Add a test and remove the bug reports with an explanation. Fixes golang/go#69616 Change-Id: Id73aab618880acf85b3c63e5b2275ab01ac2c1e9 Reviewed-on: https://go-review.googlesource.com/c/tools/+/684615 Reviewed-by: Madeline Kalil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Robert Findley <[email protected]>
1 parent ce10b6b commit bf1b00e

File tree

3 files changed

+56
-15
lines changed

3 files changed

+56
-15
lines changed

gopls/internal/golang/comment.go

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@ import (
1313
"go/token"
1414
"go/types"
1515
pathpkg "path"
16-
"slices"
1716
"strings"
1817

1918
"golang.org/x/tools/gopls/internal/cache"
2019
"golang.org/x/tools/gopls/internal/cache/parsego"
2120
"golang.org/x/tools/gopls/internal/protocol"
2221
"golang.org/x/tools/gopls/internal/settings"
2322
"golang.org/x/tools/gopls/internal/util/astutil"
24-
"golang.org/x/tools/gopls/internal/util/bug"
2523
"golang.org/x/tools/gopls/internal/util/safetoken"
2624
)
2725

@@ -61,7 +59,7 @@ func DocCommentToMarkdown(text string, options *settings.Options) string {
6159
// docLinkDefinition finds the definition of the doc link in comments at pos.
6260
// If there is no reference at pos, returns errNoCommentReference.
6361
func docLinkDefinition(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, pos token.Pos) ([]protocol.Location, error) {
64-
obj, _, err := parseDocLink(pkg, pgf, pos)
62+
obj, _, err := resolveDocLink(pkg, pgf, pos)
6563
if err != nil {
6664
return nil, err
6765
}
@@ -72,9 +70,9 @@ func docLinkDefinition(ctx context.Context, snapshot *cache.Snapshot, pkg *cache
7270
return []protocol.Location{loc}, nil
7371
}
7472

75-
// parseDocLink parses a doc link in a comment such as [fmt.Println]
73+
// resolveDocLink parses a doc link in a comment such as [fmt.Println]
7674
// and returns the symbol at pos, along with the link's start position.
77-
func parseDocLink(pkg *cache.Package, pgf *parsego.File, pos token.Pos) (types.Object, protocol.Range, error) {
75+
func resolveDocLink(pkg *cache.Package, pgf *parsego.File, pos token.Pos) (types.Object, protocol.Range, error) {
7876
var comment *ast.Comment
7977
for _, cg := range pgf.File.Comments {
8078
for _, c := range cg.List {
@@ -154,15 +152,10 @@ func lookupDocLinkSymbol(pkg *cache.Package, pgf *parsego.File, name string) typ
154152
// allowing for non-renaming and renaming imports.
155153
fileScope := pkg.TypesInfo().Scopes[pgf.File]
156154
if fileScope == nil {
157-
// This is theoretically possible if pgf is a GoFile but not a
158-
// CompiledGoFile. However, we do not know how to produce such a package
159-
// without using an external GoPackagesDriver.
160-
// See if this is the source of golang/go#70635
161-
if slices.Contains(pkg.CompiledGoFiles(), pgf) {
162-
bug.Reportf("missing file scope for compiled file")
163-
} else {
164-
bug.Reportf("missing file scope for non-compiled file")
165-
}
155+
// As we learned in golang/go#69616, any file may not be Scopes!
156+
// - A non-compiled Go file (such as unsafe.go) won't be in Scopes.
157+
// - A (technically) compiled go file with the wrong package name won't be
158+
// in Scopes, as it will be skipped by go/types.
166159
return nil
167160
}
168161
pkgname, ok := fileScope.Lookup(prefix).(*types.PkgName) // ok => prefix is imported name

gopls/internal/golang/hover.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
246246
}
247247

248248
// Handle hovering over a doc link
249-
if obj, rng, _ := parseDocLink(pkg, pgf, pos); obj != nil {
249+
if obj, rng, _ := resolveDocLink(pkg, pgf, pos); obj != nil {
250250
// Built-ins have no position.
251251
if isBuiltin(obj) {
252252
h, err := hoverBuiltin(ctx, snapshot, obj)

gopls/internal/test/integration/misc/definition_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,3 +699,51 @@ func Foo() {
699699
}
700700
})
701701
}
702+
703+
func TestCommentDefinition_Issue69616(t *testing.T) {
704+
// This test exercises a few edge cases discovered by telemetry in
705+
// golang/go#69616, namely situations where a parsed Go file might
706+
// not have an associated scope in the package types.Info.
707+
//
708+
// The files below set up two types of edge cases:
709+
// - a 'compiled' Go file that isn't actually type-checked, because it has
710+
// the wrong package name
711+
// - a non-compiled Go file (unsafe.go).
712+
const src = `
713+
-- go.mod --
714+
module mod.com
715+
716+
go 1.21
717+
-- cmd/main.go --
718+
package main
719+
720+
import "unsafe"
721+
722+
var _ = unsafe.Offsetof
723+
724+
func Foo() {}
725+
-- cmd/x.go --
726+
package x
727+
728+
// Bar is like [Foo]
729+
func Bar() {}
730+
`
731+
732+
Run(t, src, func(t *testing.T, env *Env) {
733+
// First, check that we don't produce a crash or bug when
734+
// finding definitions in a 'compiled' go file that isn't actually type
735+
// checked.
736+
env.OpenFile("cmd/x.go")
737+
_, _ = env.Editor.Definitions(env.Ctx, env.RegexpSearch("cmd/x.go", "()Foo"))
738+
739+
// Next, go to the unsafe package, and find the doc link to [Sizeof].
740+
// It will also fail to resolve, because unsafe.go isn't compiled, but
741+
// again should not panic or result in a bug.
742+
env.OpenFile("cmd/main.go")
743+
loc := env.FirstDefinition(env.RegexpSearch("cmd/main.go", `unsafe\.(Offsetof)`))
744+
unsafePath := loc.URI.Path()
745+
env.OpenFile(unsafePath)
746+
_, _ = env.Editor.Definitions(env.Ctx,
747+
env.RegexpSearch(unsafePath, `\[()Sizeof\]`))
748+
})
749+
}

0 commit comments

Comments
 (0)