Skip to content

Commit f11abcb

Browse files
adonovangopherbot
authored andcommitted
internal/analysisinternal: permit Fix.End slightly beyond EOF
This CL fixes by far the most prolific source of gopls telemetry field reports: the unreachable analyzer often reports diagnostics at the end of a truncated file; because of problems with AST the fix's end position may be beyond EOF, causing ValidateFixes to fail, and gopls to report a bug. The mitigation is to make validation tolerant of fixes whose end is just slightly beyond EOF, and to clamp them to EOF. + regression test Fixes golang/go#71659 Fixes golang/go#71812 Change-Id: Ib68a38d0797c9274eaf3d59fabd45cc120f1dd36 Reviewed-on: https://go-review.googlesource.com/c/tools/+/666675 Auto-Submit: Alan Donovan <[email protected]> Commit-Queue: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 46e932f commit f11abcb

File tree

4 files changed

+39
-1
lines changed

4 files changed

+39
-1
lines changed

go/analysis/passes/unreachable/unreachable.go

+3
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ func (d *deadState) findDead(stmt ast.Stmt) {
188188
case *ast.EmptyStmt:
189189
// do not warn about unreachable empty statements
190190
default:
191+
// (This call to pass.Report is a frequent source
192+
// of diagnostics beyond EOF in a truncated file;
193+
// see #71659.)
191194
d.pass.Report(analysis.Diagnostic{
192195
Pos: stmt.Pos(),
193196
End: stmt.End(),

gopls/internal/cache/analysis.go

+4
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,10 @@ func (act *action) exec(ctx context.Context) (any, *actionSummary, error) {
11221122
ResultOf: inputs,
11231123
Report: func(d analysis.Diagnostic) {
11241124
// Assert that SuggestedFixes are well formed.
1125+
//
1126+
// ValidateFixes allows a fix.End to be slightly beyond
1127+
// EOF to avoid spurious assertions when reporting
1128+
// fixes as the end of truncated files; see #71659.
11251129
if err := analysisinternal.ValidateFixes(apkg.pkg.FileSet(), analyzer, d.SuggestedFixes); err != nil {
11261130
bug.Reportf("invalid SuggestedFixes: %v", err)
11271131
d.SuggestedFixes = nil
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
This input causes the unreachable analyzer to report a diagnostic
2+
about the var decl statement. Since the computed End pos of
3+
ast.StructType is beyond EOF, validation of SuggestedFixes fails.
4+
This used to trigger an assertion in gopls' analysis driver.
5+
6+
See golang/go#71659 (and also #71812).
7+
8+
-- flags --
9+
-ignore_extra_diags
10+
11+
-- go.mod --
12+
module example.com
13+
go 1.18
14+
15+
-- a/a.go --
16+
package a
17+
func _() { return; var x struct{

internal/analysisinternal/analysis.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -439,11 +439,25 @@ func validateFix(fset *token.FileSet, fix *analysis.SuggestedFix) error {
439439
if file == nil {
440440
return fmt.Errorf("no token.File for TextEdit.Pos (%v)", edit.Pos)
441441
}
442+
fileEnd := token.Pos(file.Base() + file.Size())
442443
if end := edit.End; end.IsValid() {
443444
if end < start {
444445
return fmt.Errorf("TextEdit.Pos (%v) > TextEdit.End (%v)", edit.Pos, edit.End)
445446
}
446447
endFile := fset.File(end)
448+
if endFile != file && end < fileEnd+10 {
449+
// Relax the checks below in the special case when the end position
450+
// is only slightly beyond EOF, as happens when End is computed
451+
// (as in ast.{Struct,Interface}Type) rather than based on
452+
// actual token positions. In such cases, truncate end to EOF.
453+
//
454+
// This is a workaround for #71659; see:
455+
// https://github.com/golang/go/issues/71659#issuecomment-2651606031
456+
// A better fix would be more faithful recording of token
457+
// positions (or their absence) in the AST.
458+
edit.End = fileEnd
459+
continue
460+
}
447461
if endFile == nil {
448462
return fmt.Errorf("no token.File for TextEdit.End (%v; File(start).FileEnd is %d)", end, file.Base()+file.Size())
449463
}
@@ -454,7 +468,7 @@ func validateFix(fset *token.FileSet, fix *analysis.SuggestedFix) error {
454468
} else {
455469
edit.End = start // update the SuggestedFix
456470
}
457-
if eof := token.Pos(file.Base() + file.Size()); edit.End > eof {
471+
if eof := fileEnd; edit.End > eof {
458472
return fmt.Errorf("end is (%v) beyond end of file (%v)", edit.End, eof)
459473
}
460474

0 commit comments

Comments
 (0)