fix(lsp): validate line numbers in semantic tokens and inlay hints

The error 'Invalid line: out of range' was caused by semantic tokens
and inlay hints using variable line numbers that might be out of bounds
for the current document content. This could happen when the cached
variables from a previous document version have line numbers that don't
match the current content.

Added validation to both textDocument_semanticTokensFull and
textDocument_inlayHint to ensure line numbers are within the valid
range (0 to total_lines - 1) before processing.
This commit is contained in:
2026-02-19 11:56:09 +01:00
parent 313f5035ee
commit 1808edc1f0
+12 -2
View File
@@ -568,8 +568,14 @@ function handlers.textDocument_semanticTokensFull(params)
for line in doc.content:gmatch("([^\n]*)\n") do for line in doc.content:gmatch("([^\n]*)\n") do
table.insert(lines, line) table.insert(lines, line)
end end
local total_lines = #lines
local function add_token(line, startChar, length, tokenType) local function add_token(line, startChar, length, tokenType)
-- Validate line number is within bounds
if line < 0 or line >= total_lines then
return
end
local deltaLine = line local deltaLine = line
local deltaStart = startChar local deltaStart = startChar
if #tokens >= 4 then if #tokens >= 4 then
@@ -595,7 +601,8 @@ function handlers.textDocument_semanticTokensFull(params)
if doc.variables then if doc.variables then
for var_name, info in pairs(doc.variables) do for var_name, info in pairs(doc.variables) do
if info.line == lineNum then -- Validate variable line number is within bounds
if info.line and info.line >= 0 and info.line < total_lines and info.line == lineNum then
local startChar = line:find(var_name, 1, true) local startChar = line:find(var_name, 1, true)
if startChar then if startChar then
add_token(lineNum, startChar - 1, #var_name, "variable") add_token(lineNum, startChar - 1, #var_name, "variable")
@@ -673,11 +680,14 @@ function handlers.textDocument_inlayHint(params)
table.insert(lines, line) table.insert(lines, line)
end end
local total_lines = #lines
for i, line in ipairs(lines) do for i, line in ipairs(lines) do
local lineNum = i - 1 local lineNum = i - 1
if doc.variables then if doc.variables then
for var_name, info in pairs(doc.variables) do for var_name, info in pairs(doc.variables) do
if info.line == lineNum and info.data_type and info.data_type ~= "unknown" then -- Validate line number is within bounds
if info.line and info.line >= 0 and info.line < total_lines and info.line == lineNum and info.data_type and info.data_type ~= "unknown" then
local colonPos = line:find(":", 1, true) local colonPos = line:find(":", 1, true)
if colonPos then if colonPos then
table.insert(hints, { table.insert(hints, {