local stage = {}
|
|
stage.warnings = {
|
["321"] = {message_format = "accessing uninitialized variable {name!}", fields = {"name"}},
|
["341"] = {message_format = "mutating uninitialized variable {name!}", fields = {"name"}}
|
}
|
|
local function detect_uninit_access_in_line(chstate, line)
|
for _, item in ipairs(line.items) do
|
for _, action_key in ipairs({"accesses", "mutations"}) do
|
local code = action_key == "accesses" and "321" or "341"
|
local item_var_map = item[action_key]
|
|
if item_var_map then
|
for var, accessing_nodes in pairs(item_var_map) do
|
-- If there are no values at all reaching this access, not even the empty one,
|
-- this item (or a closure containing it) is not reachable from variable definition.
|
-- It will be reported as unreachable code, no need to report uninitalized accesses in it.
|
if item.used_values[var] then
|
-- If this variable is has only one, empty value then it's already reported as never set,
|
-- no need to report each access.
|
if not (#var.values == 1 and var.values[1].empty) then
|
local all_possible_values_empty = true
|
|
for _, possible_value in ipairs(item.used_values[var]) do
|
if not possible_value.empty then
|
all_possible_values_empty = false
|
break
|
end
|
end
|
|
if all_possible_values_empty then
|
for _, accessing_node in ipairs(accessing_nodes) do
|
chstate:warn_range(code, accessing_node, {
|
name = accessing_node[1]
|
})
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
|
-- Warns about accesses and mutations that don't resolve to any values except initial empty one.
|
function stage.run(chstate)
|
for _, line in ipairs(chstate.lines) do
|
detect_uninit_access_in_line(chstate, line)
|
end
|
end
|
|
return stage
|