Skip to content

Commit 502b93c

Browse files
committed
gopls/internal/lsp: tolerate missing end position in RelatedInformation
Fix the panic reported in #56270, allowing RelatedInformation.End to be missing. Fixes golang/go#56270 Change-Id: I5f2dc27cf149c324f39ddbb056862434fe38f730 Reviewed-on: https://go-review.googlesource.com/c/tools/+/443337 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Alan Donovan <[email protected]> gopls-CI: kokoro <[email protected]> Run-TryBot: Robert Findley <[email protected]>
1 parent d67c3ad commit 502b93c

File tree

6 files changed

+51
-8
lines changed

6 files changed

+51
-8
lines changed

go/analysis/diagnostic.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type Diagnostic struct {
3737
// declaration.
3838
type RelatedInformation struct {
3939
Pos token.Pos
40-
End token.Pos
40+
End token.Pos // optional
4141
Message string
4242
}
4343

gopls/internal/lsp/cache/errors.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,11 @@ func relatedInformation(pkg *pkg, fset *token.FileSet, diag *analysis.Diagnostic
334334
if tokFile == nil {
335335
return nil, bug.Errorf("no file for %q diagnostic position", diag.Category)
336336
}
337-
spn, err := span.NewRange(tokFile, related.Pos, related.End).Span()
337+
end := related.End
338+
if !end.IsValid() {
339+
end = related.Pos
340+
}
341+
spn, err := span.NewRange(tokFile, related.Pos, end).Span()
338342
if err != nil {
339343
return nil, err
340344
}

gopls/internal/lsp/regtest/env.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import (
1111
"sync"
1212
"testing"
1313

14-
"golang.org/x/tools/internal/jsonrpc2/servertest"
1514
"golang.org/x/tools/gopls/internal/lsp/fake"
1615
"golang.org/x/tools/gopls/internal/lsp/protocol"
16+
"golang.org/x/tools/internal/jsonrpc2/servertest"
1717
)
1818

1919
// Env holds the building blocks of an editor testing environment, providing
@@ -119,7 +119,7 @@ func (s State) String() string {
119119
for name, params := range s.diagnostics {
120120
fmt.Fprintf(&b, "\t%s (version %d):\n", name, int(params.Version))
121121
for _, d := range params.Diagnostics {
122-
fmt.Fprintf(&b, "\t\t(%d, %d): %s\n", int(d.Range.Start.Line), int(d.Range.Start.Character), d.Message)
122+
fmt.Fprintf(&b, "\t\t(%d, %d) [%s]: %s\n", int(d.Range.Start.Line), int(d.Range.Start.Character), d.Source, d.Message)
123123
}
124124
}
125125
b.WriteString("\n")

gopls/internal/lsp/source/options.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -1306,8 +1306,8 @@ func (r *OptionResult) asBoolMap() map[string]bool {
13061306
}
13071307
m := make(map[string]bool)
13081308
for a, enabled := range all {
1309-
if enabled, ok := enabled.(bool); ok {
1310-
m[a] = enabled
1309+
if e, ok := enabled.(bool); ok {
1310+
m[a] = e
13111311
} else {
13121312
r.parseErrorf("invalid type %T for map key %q", enabled, a)
13131313
return m

gopls/internal/regtest/misc/staticcheck_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,40 @@ var FooErr error = errors.New("foo")
7474
)
7575
})
7676
}
77+
78+
// Test for golang/go#56270: an analysis with related info should not panic if
79+
// analysis.RelatedInformation.End is not set.
80+
func TestStaticcheckRelatedInfo(t *testing.T) {
81+
testenv.NeedsGo1Point(t, 17) // staticcheck is only supported at Go 1.17+
82+
const files = `
83+
-- go.mod --
84+
module mod.test
85+
86+
go 1.18
87+
-- p.go --
88+
package p
89+
90+
import (
91+
"fmt"
92+
)
93+
94+
func Foo(enabled interface{}) {
95+
if enabled, ok := enabled.(bool); ok {
96+
} else {
97+
_ = fmt.Sprintf("invalid type %T", enabled) // enabled is always bool here
98+
}
99+
}
100+
`
101+
102+
WithOptions(
103+
Settings{"staticcheck": true},
104+
).Run(t, files, func(t *testing.T, env *Env) {
105+
env.OpenFile("p.go")
106+
env.Await(
107+
OnceMet(
108+
env.DoneWithOpen(),
109+
env.DiagnosticAtRegexpFromSource("p.go", ", (enabled)", "SA9008"),
110+
),
111+
)
112+
})
113+
}

gopls/internal/span/token.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ type Range struct {
1919
Start, End token.Pos // both IsValid()
2020
}
2121

22-
// NewRange creates a new Range from a token.File and two valid positions within it.
22+
// NewRange creates a new Range from a token.File and two positions within it.
23+
// The given start position must be valid; if end is invalid, start is used as
24+
// the end position.
2325
//
2426
// (If you only have a token.FileSet, use file = fset.File(start). But
2527
// most callers know exactly which token.File they're dealing with and
@@ -33,7 +35,7 @@ func NewRange(file *token.File, start, end token.Pos) Range {
3335
panic("invalid start token.Pos")
3436
}
3537
if !end.IsValid() {
36-
panic("invalid end token.Pos")
38+
end = start
3739
}
3840

3941
// TODO(adonovan): ideally we would make this stronger assertion:

0 commit comments

Comments
 (0)