The Boston Diaries

The ongoing saga of a programmer who doesn't live in Boston, nor does he even like Boston, but yet named his weblog/journal “The Boston Diaries.”

Go figure.

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 = ...
  -- ...

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 = ...
  -- ...


function foo(param1,param2)
  local param1 = param1 or "default value" -- luacheck: ignore
  local param2 = param2 or 3 -- luacheck: ignore
  local a = ...
  -- ...

Overall, I'm glad I found this tool. It's been a real eye opener.

Obligatory Picture

[The future's so bright, I gotta wear shades]

Obligatory Contact Info

Obligatory Feeds

Obligatory Links

Obligatory Miscellaneous

You have my permission to link freely to any entry here. Go ahead, I won't bite. I promise.

The dates are the permanent links to that day's entries (or entry, if there is only one entry). The titles are the permanent links to that entry only. The format for the links are simple: Start with the base link for this site:, then add the date you are interested in, say 2000/08/01, so that would make the final URL:

You can also specify the entire month by leaving off the day portion. You can even select an arbitrary portion of time.

You may also note subtle shading of the links and that's intentional: the “closer” the link is (relative to the page) the “brighter” it appears. It's an experiment in using color shading to denote the distance a link is from here. If you don't notice it, don't worry; it's not all that important.

It is assumed that every brand name, slogan, corporate name, symbol, design element, et cetera mentioned in these pages is a protected and/or trademarked entity, the sole property of its owner(s), and acknowledgement of this status is implied.

Copyright © 1999-2024 by Sean Conner. All Rights Reserved.