1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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