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{}