Friday, April 24, 2015
Notes about a Lua lint checker
Luacheck is a static analyzer and a linter for Lua. Luacheck detects various issues such as usage of undefined global variables, unused variables and values, accessing uninitialized variables, unreachable code and more.
The one real issue I have with Lua is its dynamic typing. Of all the bugs I fix in my own Lua code, I would say that the majority are due to typos (wrong variable name) or an unexpected type. So I was quite happy to come across and try out Luacheck. And fortunately, it's pretty straightforward to run.
I ran it over “Project: Sippy-
Cup” and … wow. The extensive regression test I have has already flushed
out the typos and the unexpected type errors I tend to make. But Luacheck
found quite a few unused variables (which is nice—it also found a bunch of
unsused LPeg expressions) and a ton of unintentional
global variables (because I forgot to declare them with
local
).
The output is easy to read (here's a representative sample from some non- work related code I have):
Checking ptest-cr-select.lua Failure ptest-cr-select.lua:53:9: variable amount was previously defined as an argument on line 52 ptest-cr-select.lua:128:9: variable okay is never accessed ptest-cr-select.lua:193:40: unused argument event ptest-cr-select.lua:197:43: shadowing upvalue conn on line 194 ptest-cr-select.lua:213:21: shadowing upvalue argument event on line 193 ptest-cr-select.lua:215:15: unused variable rem ptest-cr-select.lua:215:15: shadowing upvalue rem on line 194 Total: 7 warnings / 0 errors in 1 file
About the only false positive it finds is this idiom:
function foo(param1,param2) local param1 = param1 or "default value" local param2 = param2 or 3 local a = ... -- ... end
where it will flag param1
and param2
as
shadowing an upvalue. This idiom though, is used to provide a default value
if a parameter isn't given to a function. It's easy enough to fix,
either:
function foo(param1,param2) param1 = param1 or "default value" param2 = param2 or 3 local a = ... -- ... end
or
function foo(param1,param2) local param1 = param1 or "default value" -- luacheck: ignore local param2 = param2 or 3 -- luacheck: ignore local a = ... -- ... end
Overall, I'm glad I found this tool. It's been a real eye opener.