Defer need-check-nil and clean up stale suppressions

emmylua deserialises an unknown diagnostic code to a catch all that
matches no checker, so every `invisible`, `nil-check` and
`global-element` suppression was silently doing nothing. Renamed to the
emmylua codes. `name-style-check` has no equivalent and is dropped, it
was already disabled under luals.

The `get_tile` suppressions referenced an api typedef bug from 2024
which no longer reproduces.

need-check-nil is deferred rather than disabled on merit: a third of the
407 findings come from MapPosition and BoundingBox being aliased as
`struct|[double, double]`, so every `entity.position.x` reads as
possibly nil. The rest need per site knowledge of runtime invariants.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
bbassie
2026-08-07 15:31:18 +00:00
co-authored by Claude Opus 5
parent b9cfbc9036
commit c233a9ab06
13 changed files with 19 additions and 23 deletions
+2
View File
@@ -18,6 +18,7 @@
}, },
"$comment-disable": "Carried over from the luals config, which had these as editor only rather than checked in ci", "$comment-disable": "Carried over from the luals config, which had these as editor only rather than checked in ci",
"$comment-unnecessary-if": "Disabled by the config fmtk generates for itself, the api union types make it unreliable", "$comment-unnecessary-if": "Disabled by the config fmtk generates for itself, the api union types make it unreliable",
"$comment-need-check-nil": "To be enabled once the backlog is cleared, a third of it is MapPosition and BoundingBox being aliased as struct|[double, double]",
"diagnostics": { "diagnostics": {
"globals": [ "__DebugAdapter", "__Profiler" ], "globals": [ "__DebugAdapter", "__Profiler" ],
"disable": [ "disable": [
@@ -26,6 +27,7 @@
"invert-if", "invert-if",
"missing-parameter", "missing-parameter",
"missing-return-value", "missing-return-value",
"need-check-nil",
"param-type-mismatch", "param-type-mismatch",
"preferred-local-alias", "preferred-local-alias",
"redefined-local", "redefined-local",
-2
View File
@@ -21,12 +21,10 @@ setmetatable(rcon_static, { __index = _G })
setmetatable(rcon_env, { __index = rcon_static }) setmetatable(rcon_env, { __index = rcon_static })
--- Some common static values which can be added now --- Some common static values which can be added now
--- @diagnostic disable: name-style-check
rcon_static.Async = Async rcon_static.Async = Async
rcon_static.ExpUtil = ExpUtil rcon_static.ExpUtil = ExpUtil
rcon_static.Commands = Commands rcon_static.Commands = Commands
rcon_static.print = Commands.print rcon_static.print = Commands.print
--- @diagnostic enable: name-style-check
--- Some common callback values which are useful when a player uses the command --- Some common callback values which are useful when a player uses the command
--- @alias ExpCommand.RconDynamic fun(player: LuaPlayer?): any --- @alias ExpCommand.RconDynamic fun(player: LuaPlayer?): any
+1 -1
View File
@@ -19,7 +19,7 @@ Commands.new("_sudo", { "exp-commands_sudo.description" })
--- @cast command ExpCommand --- @cast command ExpCommand
--- @cast parameter string --- @cast parameter string
--- @diagnostic disable-next-line: invisible --- @diagnostic disable-next-line: access-invisible
return Commands._event_handler{ return Commands._event_handler{
name = command.name, name = command.name,
tick = game.tick, tick = game.tick,
+1 -1
View File
@@ -5,7 +5,7 @@ Therefore, we advise that this should be the only file in your module to expose
Typically this would be your control file as shown in the example below Typically this would be your control file as shown in the example below
]] ]]
--- @diagnostic disable: global-element --- @diagnostic disable: global-in-non-module
-- Access using `/sc exp_groups.foo()` -- Access using `/sc exp_groups.foo()`
exp_groups = require("modules/exp_groups/control") exp_groups = require("modules/exp_groups/control")
+3 -3
View File
@@ -188,9 +188,9 @@ function Gui._ensure_consistency(event)
-- This check isn't needed, but allows the toolbar file to be deleted without modifying any lib code -- This check isn't needed, but allows the toolbar file to be deleted without modifying any lib code
if Gui.toolbar then if Gui.toolbar then
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
Gui.toolbar._create_elements(player) Gui.toolbar._create_elements(player)
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
Gui.toolbar._ensure_consistency(player) Gui.toolbar._ensure_consistency(player)
end end
end end
@@ -211,7 +211,7 @@ local function on_gui_opened(event)
if visible then if visible then
event.element = element event.element = element
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
define:raise_event(event) define:raise_event(event)
end end
end end
+1 -1
View File
@@ -29,7 +29,7 @@ Toolbar.on_gui_button_toggled = script.generate_event_name()
--- @class _ExpElement._prototype --- @class _ExpElement._prototype
--- @field on_button_toggled ExpElement.OnEventAdder<EventData.on_gui_button_toggled> --- @field on_button_toggled ExpElement.OnEventAdder<EventData.on_gui_button_toggled>
--- @diagnostic disable-next-line: invisible, inject-field --- @diagnostic disable-next-line: access-invisible, inject-field
function ExpElement._prototype.on_button_toggled(self, handler) function ExpElement._prototype.on_button_toggled(self, handler)
return self:on_event(Toolbar.on_gui_button_toggled, handler) return self:on_event(Toolbar.on_gui_button_toggled, handler)
end end
@@ -2,6 +2,6 @@ local Gui = require("modules/exp_gui")
local Roles = require("modules.exp_legacy.expcore.roles") local Roles = require("modules.exp_legacy.expcore.roles")
local Event = require("modules/exp_legacy/utils/event") local Event = require("modules/exp_legacy/utils/event")
--- @diagnostic disable invisible --- @diagnostic disable: access-invisible
Event.add(Roles.events.on_role_assigned, Gui._ensure_consistency) Event.add(Roles.events.on_role_assigned, Gui._ensure_consistency)
Event.add(Roles.events.on_role_unassigned, Gui._ensure_consistency) Event.add(Roles.events.on_role_unassigned, Gui._ensure_consistency)
+1 -1
View File
@@ -4,7 +4,7 @@ However, sometimes you need globals, for example to access functions within rcon
Therefore, we advise that this should be the only file in your module to expose globals Therefore, we advise that this should be the only file in your module to expose globals
]] ]]
--- @diagnostic disable: global-element --- @diagnostic disable: global-in-non-module
-- Access using `/sc exp_roles.foo()` -- Access using `/sc exp_roles.foo()`
exp_roles = require("modules/exp_roles/control") exp_roles = require("modules/exp_roles/control")
+1 -1
View File
@@ -55,7 +55,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" })
end end
local last = #roles_formatted local last = #roles_formatted
--- @diagnostic disable-next-line nil-check --- @diagnostic disable-next-line: need-check-nil
roles_formatted[last] = roles_formatted[last][2] roles_formatted[last] = roles_formatted[last][2]
return Commands.status.success(response) return Commands.status.success(response)
@@ -18,7 +18,6 @@ end
--- @param surface LuaSurface --- @param surface LuaSurface
--- @param position MapPosition --- @param position MapPosition
local function degrade_tile(surface, position) local function degrade_tile(surface, position)
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761
local tile = surface.get_tile(position) local tile = surface.get_tile(position)
local tile_name = tile.name local tile_name = tile.name
local degrade_tile_name = config.degrade_order[tile_name] local degrade_tile_name = config.degrade_order[tile_name]
@@ -61,7 +60,6 @@ end
--- @param position MapPosition --- @param position MapPosition
--- @return number? --- @return number?
local function get_tile_strength(surface, position) local function get_tile_strength(surface, position)
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761
local tile = surface.get_tile(position) local tile = surface.get_tile(position)
local tile_name = tile.name local tile_name = tile.name
local strength = config.strengths[tile_name] local strength = config.strengths[tile_name]
@@ -164,7 +164,6 @@ local function clear_spawn_area(surface, offset)
local get_tile = surface.get_tile local get_tile = surface.get_tile
-- Make sure a non water tile is used for filling -- Make sure a non water tile is used for filling
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761
local starting_tile = get_tile(offset) local starting_tile = get_tile(offset)
local fill_tile = starting_tile.collides_with("player") and "landfill" or starting_tile.name local fill_tile = starting_tile.collides_with("player") and "landfill" or starting_tile.name
local fill_radius = config.spawn_area.landfill_radius local fill_radius = config.spawn_area.landfill_radius
@@ -185,7 +184,6 @@ local function clear_spawn_area(surface, offset)
if dst < tile_radius_sqr then if dst < tile_radius_sqr then
-- If it is inside the decon radius always set the tile -- If it is inside the decon radius always set the tile
tiles_to_make[#tiles_to_make + 1] = { name = decon_tile, position = pos } tiles_to_make[#tiles_to_make + 1] = { name = decon_tile, position = pos }
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761
elseif dst < fill_radius_sqr and get_tile(pos).collides_with("player") then elseif dst < fill_radius_sqr and get_tile(pos).collides_with("player") then
-- If it is inside the fill radius only set the tile if it is water -- If it is inside the fill radius only set the tile if it is water
tiles_to_make[#tiles_to_make + 1] = { name = fill_tile, position = pos } tiles_to_make[#tiles_to_make + 1] = { name = fill_tile, position = pos }
@@ -27,7 +27,7 @@ function Public.show(container)
local left_panel_style = left_panel.style local left_panel_style = left_panel.style
left_panel_style.width = 300 left_panel_style.width = 300
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
for element_name in pairs(ExpElement._elements) do for element_name in pairs(ExpElement._elements) do
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = element_name } local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = element_name }
Gui.set_data(header, element_name) Gui.set_data(header, element_name)
@@ -92,18 +92,18 @@ Gui.on_click(
input_text_box.text = concat{ "ExpElement._elements[\"", element_name, "\"]" } input_text_box.text = concat{ "ExpElement._elements[\"", element_name, "\"]" }
input_text_box.style.font_color = Color.black input_text_box.style.font_color = Color.black
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
local define = ExpElement._elements[element_name] local define = ExpElement._elements[element_name]
local content = dump({ local content = dump({
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
debug = define._debug, debug = define._debug,
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
has_handlers = define._has_handlers, has_handlers = define._has_handlers,
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
track_elements = define._track_elements, track_elements = define._track_elements,
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
elements = ExpIter._scopes[element_name], elements = ExpIter._scopes[element_name],
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
data = ExpData._scopes[element_name]._raw, data = ExpData._scopes[element_name]._raw,
}) or "nil" }) or "nil"
right_panel.text = content right_panel.text = content
@@ -24,7 +24,7 @@ function Public.show(container)
local left_panel_style = left_panel.style local left_panel_style = left_panel.style
left_panel_style.width = 300 left_panel_style.width = 300
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
for token_id in pairs(Storage._registered) do for token_id in pairs(Storage._registered) do
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = token_id } local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = token_id }
Gui.set_data(header, token_id) Gui.set_data(header, token_id)