From 7aa8294462557f1ee22e53791eaeb865f919416e Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Thu, 15 Jul 2021 17:33:50 -0400 Subject: [PATCH] internal/lsp: handle panic in fix AST I'm not sure how this can happen, but it seems possible that a bad expression might somehow have an invalid position. Fixes golang/go#47231 Change-Id: I0794bdfb66f668fc375e9fe561c9f239c8b92492 Reviewed-on: https://go-review.googlesource.com/c/tools/+/334892 Trust: Rebecca Stambler Run-TryBot: Rebecca Stambler gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Robert Findley --- internal/lsp/cache/parse.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/internal/lsp/cache/parse.go b/internal/lsp/cache/parse.go index f7cf1af0bd..d455a252b8 100644 --- a/internal/lsp/cache/parse.go +++ b/internal/lsp/cache/parse.go @@ -1070,7 +1070,17 @@ func fixArrayType(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte exprBytes := make([]byte, 0, int(to-from)+3) // Avoid doing tok.Offset(to) since that panics if badExpr ends at EOF. - exprBytes = append(exprBytes, src[tok.Offset(from):tok.Offset(to-1)+1]...) + // It also panics if the position is not in the range of the file, and + // badExprs may not necessarily have good positions, so check first. + if !inRange(tok, from) { + return false + } + if !inRange(tok, to-1) { + return false + } + fromOffset := tok.Offset(from) + toOffset := tok.Offset(to-1) + 1 + exprBytes = append(exprBytes, src[fromOffset:toOffset]...) exprBytes = bytes.TrimSpace(exprBytes) // If our expression ends in "]" (e.g. "[]"), add a phantom selector @@ -1102,6 +1112,12 @@ func fixArrayType(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte return replaceNode(parent, bad, at) } +// inRange reports whether the given position is in the given token.File. +func inRange(tok *token.File, pos token.Pos) bool { + size := tok.Pos(tok.Size()) + return int(pos) >= tok.Base() && pos <= size +} + // precedingToken scans src to find the token preceding pos. func precedingToken(pos token.Pos, tok *token.File, src []byte) token.Token { s := &scanner.Scanner{}