Skip to content

Commit d0930db

Browse files
committed
gopls/internal/lsp/cache: fix bug reports from toGobDiagnostics
Fix two cases that could lead to the bug reports related to position conversion reported in golang/go#64547: 1. The lostcancel analyzer reports diagnostics for a synthetic range that could overflow the file. 2. The cgocall analyzer, which runs despite errors, could report diagnostics for invalid "fixed" positions. Issue (1) was easy enough to prove with a test, though (2) is admittedly just a hypothesis. Nevertheless, we should close the telemetry-derived issue and see if it recurs. Fixes golang/go#64547 Change-Id: Ie69bdae474abdd25235d856fc0ae0bfaf7e214ed Reviewed-on: https://go-review.googlesource.com/c/tools/+/556815 Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 1871a2e commit d0930db

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

go/analysis/passes/lostcancel/lostcancel.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,18 @@ func runFunc(pass *analysis.Pass, node ast.Node) {
172172
if ret := lostCancelPath(pass, g, v, stmt, sig); ret != nil {
173173
lineno := pass.Fset.Position(stmt.Pos()).Line
174174
pass.ReportRangef(stmt, "the %s function is not used on all paths (possible context leak)", v.Name())
175-
pass.ReportRangef(ret, "this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno)
175+
176+
pos, end := ret.Pos(), ret.End()
177+
// golang/go#64547: cfg.Block.Return may return a synthetic
178+
// ReturnStmt that overflows the file.
179+
if pass.Fset.File(pos) != pass.Fset.File(end) {
180+
end = pos
181+
}
182+
pass.Report(analysis.Diagnostic{
183+
Pos: pos,
184+
End: end,
185+
Message: fmt.Sprintf("this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno),
186+
})
176187
}
177188
}
178189
}

go/cfg/cfg.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,11 @@ func (b *Block) String() string {
113113
return fmt.Sprintf("block %d (%s)", b.Index, b.comment)
114114
}
115115

116-
// Return returns the return statement at the end of this block if present, nil otherwise.
116+
// Return returns the return statement at the end of this block if present, nil
117+
// otherwise.
118+
//
119+
// When control falls off the end of the function, the ReturnStmt is synthetic
120+
// and its [ast.Node.End] position may be beyond the end of the file.
117121
func (b *Block) Return() (ret *ast.ReturnStmt) {
118122
if len(b.Nodes) > 0 {
119123
ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt)

gopls/internal/lsp/cache/analysis.go

+19-3
Original file line numberDiff line numberDiff line change
@@ -1269,10 +1269,21 @@ func (act *action) exec() (interface{}, *actionSummary, error) {
12691269
factFilter[reflect.TypeOf(f)] = true
12701270
}
12711271

1272+
// If the package contains "fixed" files, it's not necessarily an error if we
1273+
// can't convert positions.
1274+
hasFixedFiles := false
1275+
for _, p := range pkg.parsed {
1276+
if p.Fixed() {
1277+
hasFixedFiles = true
1278+
break
1279+
}
1280+
}
1281+
12721282
// posToLocation converts from token.Pos to protocol form.
12731283
// TODO(adonovan): improve error messages.
12741284
posToLocation := func(start, end token.Pos) (protocol.Location, error) {
12751285
tokFile := pkg.fset.File(start)
1286+
12761287
for _, p := range pkg.parsed {
12771288
if p.Tok == tokFile {
12781289
if end == token.NoPos {
@@ -1281,8 +1292,11 @@ func (act *action) exec() (interface{}, *actionSummary, error) {
12811292
return p.PosLocation(start, end)
12821293
}
12831294
}
1284-
return protocol.Location{},
1285-
bug.Errorf("internal error: token.Pos not within package")
1295+
errorf := bug.Errorf
1296+
if hasFixedFiles {
1297+
errorf = fmt.Errorf
1298+
}
1299+
return protocol.Location{}, errorf("token.Pos not within package")
12861300
}
12871301

12881302
// Now run the (pkg, analyzer) action.
@@ -1299,7 +1313,9 @@ func (act *action) exec() (interface{}, *actionSummary, error) {
12991313
Report: func(d analysis.Diagnostic) {
13001314
diagnostic, err := toGobDiagnostic(posToLocation, analyzer, d)
13011315
if err != nil {
1302-
bug.Reportf("internal error converting diagnostic from analyzer %q: %v", analyzer.Name, err)
1316+
if !hasFixedFiles {
1317+
bug.Reportf("internal error converting diagnostic from analyzer %q: %v", analyzer.Name, err)
1318+
}
13031319
return
13041320
}
13051321
diagnostics = append(diagnostics, diagnostic)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
This test checks the fix for golang/go#64547: the lostcancel analyzer reports
2+
diagnostics that overflow the file.
3+
4+
-- p.go --
5+
package p
6+
7+
import "context"
8+
9+
func _() {
10+
_, cancel := context.WithCancel(context.Background()) //@diag("_, cancel", re"not used on all paths")
11+
if false {
12+
cancel()
13+
}
14+
} //@diag("}", re"may be reached without using the cancel")

0 commit comments

Comments
 (0)