Luacheck
相关工具推荐
| 工具 | 说明 |
|---|---|
| StyLua | Lua 代码格式化工具,与 Luacheck 互补 |
| Pre-commit | Git pre-commit 钩子管理框架 |
1. 简介
Luacheck 是一款针对 Lua 语言的静态分析器和代码检查工具(Linter)。它能够深入解析 Lua 代码的语法和语义,检测多种代码问题,包括:使用未定义的全局变量、修改只读全局变量、未使用的变量和值、访问未初始化的变量、不可达代码、变量遮蔽(shadowing)、空分支、空语句、圈复杂度过高、行长度超限等。Luacheck 自身使用 Lua 编写,支持在 Lua 5.1 - 5.4 及 LuaJIT 上运行。
- 主要检查语言:Lua 5.1-5.4、LuaJIT
- 主要检查能力:检测未定义全局变量、未使用变量、不可达代码、变量遮蔽等多种代码问题;涵盖代码质量检查(Linting & Static Analysis)
- 核心检查原理:基于 Lua 解析器生成 AST 进行静态分析
- 检查规则/选项:51 个警告代码(按全局变量、未使用变量、未使用值、遮蔽声明、控制/数据流、格式问题 6 大类组织),全量警告代码列表
- GitHub 仓库:https://github.com/luarocks/luacheck(445 stars)
- 开源协议:MIT
- 最新稳定版本:v1.2.0
- 运行环境要求:需 Lua 5.1/5.2/5.3/5.4 或 LuaJIT;通过 LuaRocks 安装
- 误报率:低
2. 官方文档
核心文档
| 文档 | 链接 |
|---|---|
| GitHub 仓库 | https://github.com/luarocks/luacheck |
| 官方文档(Read the Docs) | https://luacheck.readthedocs.io/en/stable/ |
| 命令行接口 | https://luacheck.readthedocs.io/en/stable/cli.html |
| 警告类型完整列表 | https://luacheck.readthedocs.io/en/stable/warnings.html |
| 配置文件 | https://luacheck.readthedocs.io/en/stable/config.html |
| 内联选项 | https://luacheck.readthedocs.io/en/stable/inline.html |
| Luacheck 模块接口 | https://luacheck.readthedocs.io/en/stable/module.html |
| GitHub Releases | https://github.com/luarocks/luacheck/releases |
警告类型速查
Luacheck 的警告采用三位数字编码,首位数字代表问题类别(详见警告类型完整列表):
| 类别 | 编码范围 | 说明 |
|---|---|---|
| 全局变量 | 1xx | 未定义全局变量访问/设置(111-113)、只读全局变量修改(121-122)、未使用隐式定义全局变量(131)、未定义字段访问/设置(142-143) |
| 未使用变量/值 | 2xx | 未使用的局部变量(211)、未使用的参数(212)、未使用的循环变量(213)、已使用变量提示(214)、未赋值/未访问(221-241) |
| 未使用值(次要) | 3xx | 未使用的赋值(311-314)、访问未初始化变量(321)、赋值未使用(331)、修改未初始化变量(341) |
| 变量遮蔽 | 4xx | 重定义局部变量/参数/循环变量(411-413)、遮蔽局部变量/参数/循环变量(421-423)、遮蔽上值(431-433) |
| 控制流与数据流 | 5xx | 不可达代码(511)、最多执行一次的循环(512)、未使用标签(521)、不平衡赋值(531-532)、空块/空分支(541-542)、空语句(551)、圈复杂度过高(561)、反向 for 循环(571)、否定问题(581-582) |
| 格式问题 | 6xx | 空白行(611)、行尾空白(612-614)、缩进不一致(621)、行过长(631) |
3. 社区优秀实践
3.1 Kong(Kong/kong)
- 仓库:https://github.com/Kong/kong
- 实践特点:Kong 是主流开源 API 网关,基于 OpenResty/Nginx 构建,核心逻辑使用 Lua 编写。Kong 在项目中配置了
.luacheckrc,使用std = "ngx_lua"标准并定义了 Kong 特有的全局变量(如_KONG、kong、ngx.IS_CLI)。配置中针对不同目录设置了差异化规则,例如测试文件使用std = "ngx_lua+busted",特定插件目录添加了额外的只读全局变量。Kong 还排除了 Bazel 构建产物和无效模块文件。 - 配置文件:.luacheckrc
3.2 Luanti / 原 Minetest(luanti-org/luanti)
- 仓库:https://github.com/luanti-org/luanti
- 实践特点:Luanti 是开源体素游戏引擎(原 Minetest),大量使用 Lua 编写游戏逻辑和 Mod。项目配置了详细的
.luacheckrc,定义了引擎注入的大量只读全局变量(如ItemStack、VoxelArea、vector等),并针对不同子目录设置了自定义全局变量覆盖。配置中忽略了未使用的隐式定义全局变量(131)和上值遮蔽(431/432),允许在顶层作用域隐式定义全局变量(allow_defined_top = true),并关闭了未使用参数检查(unused_args = false)。 - 配置文件:.luacheckrc
3.3 Luacheck 自身(lunarmodules/luacheck)
- 仓库:https://github.com/luarocks/luacheck
- 实践特点:Luacheck 项目自身使用 Luacheck 进行自检,其
.luacheckrc是一个精简但实用的参考配置。使用std = "min"(各 Lua 版本全局变量的交集)确保代码兼容性,启用了缓存(cache = true),通过include_files限定检查范围,并排除了 vendor 目录。此外,Luacheck 仓库还提供了.pre-commit-hooks.yaml,是 Lua 项目使用 pre-commit 集成的参考。 - 配置文件:.luacheckrc
- pre-commit 钩子定义:.pre-commit-hooks.yaml
4. 工具配置说明
4.1 配置文件说明
Luacheck 按以下顺序查找配置文件(优先级从高到低):
- CLI 参数
--config指定的路径 - 当前目录的
.luacheckrc - 逐级向上搜索父目录的
.luacheckrc,直到文件系统根目录 - 默认配置路径(
--default-config):Linux/macOS 为$XDG_CONFIG_HOME/luacheck/.luacheckrc或~/.config/luacheck/.luacheckrc,Windows 为%LOCALAPPDATA%\Luacheck\.luacheckrc
| 配置文件 | 格式 | 用途 |
|---|---|---|
.luacheckrc |
Lua 脚本 | 控制标准库版本、全局变量白名单、忽略规则、文件排除、代码风格阈值、按路径覆盖规则 |
配置文件本质是一个 Lua 脚本,可以通过赋值全局变量或返回 table 来设置选项。配置中的路径相对于配置文件所在目录解析。
4.2 .luacheckrc 配置详解
.luacheckrc 是 Luacheck 的主配置文件,控制标准库版本、全局变量、规则忽略、文件过滤与代码风格阈值。
配置项说明:
| 配置项 | 类型 | 说明 |
|---|---|---|
std |
string | Lua 标准库版本,如 lua54、lua53、ngx_lua、love;支持 +busted 等追加写法 |
globals |
string[] | 项目自定义可读写全局变量 |
read_globals |
string[] | 只读全局变量(如 vim、ngx) |
ignore |
string[] | 忽略的警告代码列表(如 212 未使用参数) |
exclude_files |
string[] | 排除的文件 glob 列表 |
max_line_length |
int | 最大行长度 |
max_cyclomatic_complexity |
int | 最大圈复杂度 |
cache |
bool | 是否启用缓存 |
files[path] |
map | 按路径覆盖规则,键为 glob,值为该路径下的配置项覆盖 |
推荐配置示例(通用 Lua 项目):
适合使用标准 Lua 编写的通用项目,以 Lua 5.4 为基础标准。
-- .luacheckrc
std = "lua54"
ignore = {
"212", -- 未使用的函数参数(以下划线 _ 开头的参数除外)
}
max_line_length = 120
max_cyclomatic_complexity = 30
cache = true
推荐配置示例(OpenResty / Nginx Lua 项目):
适合基于 OpenResty 的 Web 服务项目,使用 ngx_lua 标准预定义 ngx、ndk 等全局变量。
-- .luacheckrc
std = "ngx_lua"
globals = {
-- 项目自定义全局变量
}
ignore = {
"212", -- 未使用的函数参数
"213", -- 未使用的循环变量
}
max_line_length = 120
exclude_files = {
"vendor/*",
".luacheckrc",
}
-- 测试文件添加 busted 框架支持
files["spec/**/*_spec.lua"] = {
std = "+busted",
}
推荐配置示例(Love2D 游戏项目):
适合使用 Love2D 框架的游戏项目,使用 love 标准预定义 love 等全局变量。
-- .luacheckrc
std = "love"
globals = {
-- 游戏自定义全局变量
}
ignore = {
"212", -- 未使用的函数参数
}
max_line_length = 120
推荐配置示例(严格模式,适合高质量项目):
不忽略任何警告,所有问题都需要处理。适合新项目或对代码质量要求极高的项目。
-- .luacheckrc
std = "lua54"
ignore = {} -- 不忽略任何警告
max_line_length = 100
max_cyclomatic_complexity = 20
cache = true
-- 排除第三方代码和生成代码
exclude_files = {
"vendor/*",
"generated/*",
}
5. 主流集成方式
以下配置均基于 Luacheck v1.2.0 最新稳定版本。Lua 生态的主流集成方式为 LuaRocks + pre-commit。
5.1 pre-commit 集成
Luacheck 仓库自带 .pre-commit-hooks.yaml,可以直接作为 pre-commit hook 使用。Luacheck 的 hook 使用 language: lua,需要系统已安装 Lua 环境和 Luacheck。
.pre-commit-config.yaml 配置示例:
repos:
- repo: https://github.com/luarocks/luacheck
rev: v1.2.0
hooks:
- id: luacheck
说明:
- hook 定义使用
language: lua,执行环境依赖系统已安装的 Lua 和 Luacheck(通过 LuaRocks 安装) - pre-commit 框架默认只对 Git 暂存区的变更文件运行钩子,天然支持增量检查
- Luacheck 会自动查找项目根目录的
.luacheckrc配置文件 - 如需全量检查,可手动运行
pre-commit run luacheck --all-files
备选方案(repo: local):如果不想依赖 language: lua,也可以使用 repo: local 直接调用系统 PATH 中的 luacheck 命令:
repos:
- repo: local
hooks:
- id: luacheck
name: luacheck
entry: luacheck
language: system
types: [lua]
增量检查:pre-commit 是 Lua 项目中 Luacheck 增量检查的首选方案。pre-commit 框架默认只将暂存区中变更文件传给 hook,天然实现文件级增量检查。如需全量检查,可手动运行 pre-commit run luacheck --all-files。
5.2 IDE 集成
VS Code
Luacheck 可通过以下方式集成到 VS Code:
方案一:vscode-luacheck 扩展
安装 vscode-luacheck 扩展,提供实时的 Luacheck 诊断反馈。
方案二:配置为 lint 任务
在 .vscode/tasks.json 中配置 Luacheck 检查任务:
{
"version": "2.0.0",
"tasks": [
{
"label": "Luacheck",
"type": "shell",
"command": "luacheck",
"args": ["--codes", "--ranges", "."],
"problemMatcher": {
"pattern": {
"regexp": "^(.+):(\\d+):(\\d+)-(\\d+): \\((\\w+)\\) (.+)$",
"file": 1,
"line": 2,
"column": 3,
"endColumn": 4,
"code": 5,
"message": 6
}
},
"group": "test"
}
]
}
Vim / Neovim
方案一:Syntastic 插件
Syntastic 内置了 Luacheck checker,安装后自动检测 luacheck。
方案二:ALE 插件
" 使用 vim-plug
Plug 'dense-analysis/ale'
" 配置 ALE 使用 Luacheck
let g:ale_lua_luacheck_executable = 'luacheck'
let g:ale_lua_luacheck_options = '--std ngx_lua --codes'
方案三:null-ls / none-ls
local null_ls = require("null-ls")
null_ls.setup({
sources = {
null_ls.builtins.diagnostics.luacheck.with({
extra_args = { "--std", "ngx_lua", "--codes" },
}),
},
})
Emacs
Flycheck 内置了 Luacheck checker,安装后自动支持。
5.3 命令行使用方式
常用命令
# 检查单个文件
luacheck src/myfile.lua
# 检查整个目录(需要 LuaFileSystem)
luacheck src/
# 检查多个文件/目录
luacheck src/ tests/ foo.lua
# 从 stdin 读取并检查
cat src/file.lua | luacheck -
# 检查 rockspec 文件中指定的模块
luacheck my-package-scm-1.rockspec
# 显示警告代码和列范围
luacheck --codes --ranges src/
# 启用缓存加速重复检查
luacheck --cache src/
# 并行检查(需要 LuaLanes)
luacheck -j 4 src/
退出码含义
| 退出码 | 含义 |
|---|---|
| 0 | 没有警告或错误 |
| 1 | 有警告,但没有语法错误或无效内联选项 |
| 2 | 存在语法错误或无效的内联选项 |
| 3 | 部分文件无法检查(通常是文件名错误) |
| 4 | 关键错误(无效的 CLI 参数、配置或缓存文件) |
常用参数
| 参数 | 说明 |
|---|---|
--std <std> |
设置标准全局变量集合(max、min、lua51-lua54、luajit、ngx_lua、love、busted 等) |
--globals <name> |
添加自定义全局变量(可读写) |
--read-globals <name> |
添加只读全局变量 |
--not-globals <name> |
移除全局变量定义 |
--ignore <patt> |
过滤匹配的警告(如 --ignore 211、--ignore 1 过滤所有全局变量警告) |
--enable <patt> |
启用匹配的警告 |
--only <patt> |
只报告匹配的警告 |
--exclude-files <glob> |
排除匹配的文件(支持 **/*.lua 递归匹配) |
--include-files <glob> |
只检查匹配的文件 |
--max-line-length <n> |
设置最大行长度(默认 120) |
--max-cyclomatic-complexity <n> |
设置函数圈复杂度上限 |
--config <path> |
指定配置文件路径(默认 .luacheckrc) |
--no-config |
不加载配置文件 |
--cache |
启用缓存(默认缓存文件 .luacheckcache) |
--codes |
输出中显示警告代码 |
--ranges |
输出中显示列范围 |
--formatter <name> |
选择输出格式(default、plain、TAP、JUnit、visual_studio) |
-g / --no-global |
过滤全局变量相关警告 |
-u / --no-unused |
过滤未使用变量相关警告 |
-r / --no-redefined |
过滤变量重定义警告 |
-a / --no-unused-args |
过滤未使用参数和循环变量警告 |
-s / --no-unused-secondaries |
过滤未使用的次要值警告 |
-j <n> / --jobs <n> |
并行检查(需要 LuaLanes 库) |
-q / --quiet |
减少输出(-q 隐藏无警告文件报告,-qq 隐藏警告,-qqq 只输出摘要) |
增量检查:可通过 git diff 筛选变更文件后传给 Luacheck,或使用 --cache 加速全量检查。
基于 Git 的命令行增量方案:
# 检查暂存区中变更的 Lua 文件
luacheck $(git diff --name-only --cached --diff-filter=ACMR -- '*.lua')
# 检查工作区中相对于 main 分支变更的 Lua 文件
luacheck $(git diff --name-only origin/main...HEAD -- '*.lua')
如果变更文件列表为空,luacheck 不带文件参数时会报错,可以包装为脚本:
#!/bin/bash
CHANGED_FILES=$(git diff --name-only --cached --diff-filter=ACMR -- '*.lua')
if [ -n "$CHANGED_FILES" ]; then
echo "$CHANGED_FILES" | xargs luacheck --codes --ranges
else
echo "No Lua files to check."
fi
缓存加速全量检查:即使做全量检查,也可以使用 --cache 参数大幅提升速度,仅重新检查发生变化的文件:
luacheck --cache --codes --ranges .
缓存文件默认存储在 .luacheckcache 中。注意:--cache 必须在每次运行时都使用,而非仅首次运行。
CI 脚本调用:
GitHub Actions(手动安装)
name: Luacheck
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
luacheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Lua and Luarocks
run: |
sudo apt-get update
sudo apt-get install -y lua5.3 luarocks
- name: Install Luacheck
run: sudo luarocks install luacheck
- name: Run Luacheck
run: luacheck --codes --ranges .
GitLab CI
stages:
- lint
luacheck:
stage: lint
image: alpine:latest
before_script:
- apk add --no-cache lua5.3 luarocks
- luarocks install luacheck
script:
- luacheck --codes --ranges .
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
Docker
Luacheck 提供预构建的 Docker 镜像,适合 CI 环境使用:
# 拉取官方镜像
docker pull ghcr.io/lunarmodules/luacheck:latest
# 检查当前目录
docker run -v "$(pwd):/data" ghcr.io/lunarmodules/luacheck:latest .
# 检查单个文件
docker run -v "$(pwd):/data" ghcr.io/lunarmodules/luacheck:latest src/myfile.lua
增量检查:CI/CD 场景下可基于 git diff 筛选变更文件实现增量检查。
GitHub Actions(增量:基于 git diff)
- name: Check changed Lua files
run: |
CHANGED_FILES=$(git diff --name-only origin/main...HEAD -- '*.lua')
if [ -n "$CHANGED_FILES" ]; then
echo "$CHANGED_FILES" | xargs luacheck --codes --ranges
else
echo "No Lua files to check."
fi
对于 Lua 项目(通常规模不大),全量检查成本可控,也可以直接使用官方 Action 全量检查:
- name: Luacheck linter
uses: lunarmodules/luacheck@v1
with:
args: "--codes ."
GitLab CI(增量:基于 git diff)
script:
- |
CHANGED_FILES=$(git diff --name-only $CI_MERGE_REQUEST_DIFF_BASE_SHA...$CI_COMMIT_SHA -- '*.lua')
if [ -n "$CHANGED_FILES" ]; then
echo "$CHANGED_FILES" | xargs luacheck --codes --ranges
else
echo "No Lua files to check."
fi
5.4 GitHub Action 插件
Luacheck 提供了官方 GitHub Action,无需手动安装 Lua 和 Luacheck。
name: Luacheck
on: [push, pull_request]
jobs:
luacheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Luacheck linter
uses: lunarmodules/luacheck@v1
with:
args: "--codes ."
5.5 LuaRocks 安装(生态主流)
LuaRocks 是 Lua 生态的包管理器,是安装 Luacheck 的推荐方式。
# 安装最新版本
luarocks install luacheck
# 安装指定版本
luarocks install luacheck 1.2.0-1
# 并行检查需要额外安装 LuaLanes
luarocks install lanes
其他安装方式:
# macOS Homebrew
brew install luacheck
# 从源码安装
git clone https://github.com/luarocks/luacheck.git
cd luacheck
luarocks make
Windows 预编译二进制:从 GitHub Releases 页面下载 luacheck.exe(单文件 64 位二进制,内含 Lua 5.4.4、LuaFileSystem 和 LuaLanes)。
6. 告警抑制(屏蔽)方法
6.1 通过工具配置文件屏蔽
在 .luacheckrc 配置文件中使用 ignore、exclude_files、include_files 等选项控制检查行为。
官方文档:配置文件
-- .luacheckrc
-- 忽略特定警告代码
ignore = {
"211", -- 未使用的局部变量
"212", -- 未使用的函数参数
"213", -- 未使用的循环变量
"511", -- 不可达代码
"631", -- 行过长
}
-- 排除特定文件或目录
exclude_files = {
"vendor/*",
"generated/*",
}
-- 只检查特定文件
include_files = {"src/*.lua", "tests/*.lua"}
-- 针对特定路径忽略特定警告
files["src/generated/*.lua"] = {
ignore = { "1*" }, -- 忽略所有全局变量警告
}
-- 关闭特定类别的检查
unused_args = false -- 关闭未使用参数检查
redefined = false -- 关闭变量重定义检查
self = false -- 关闭隐式 self 参数检查
6.2 通过工具命令行参数屏蔽
官方文档:命令行选项
按警告代码过滤
# 忽略特定警告代码
luacheck --ignore 211,212,213 src/
# 忽略整个类别的警告(如所有全局变量警告 1xx)
luacheck --ignore 1 src/
# 只报告特定警告
luacheck --only 1 src/
按类别快捷开关
# 关闭全局变量检查
luacheck --no-global src/
# 关闭未使用变量检查
luacheck --no-unused src/
# 关闭未使用参数检查
luacheck --no-unused-args src/
# 关闭变量重定义检查
luacheck --no-redefined src/
# 关闭未使用次要值检查
luacheck --no-unused-secondaries src/
按文件范围过滤
# 排除特定文件
luacheck --exclude-files "vendor/*" --exclude-files "generated/*" .
# 只检查特定文件
luacheck --include-files "src/*.lua" .
通过标准库选择避免误报
# 使用 OpenResty 标准(预定义 ngx 等全局变量)
luacheck --std ngx_lua src/
# 使用 Love2D 标准(预定义 love 等全局变量)
luacheck --std love src/
# 使用最大兼容标准(包含 Lua 5.1-5.4 和 LuaJIT 的所有全局变量)
luacheck --std max src/
# 组合多个标准
luacheck --std "lua54+love" src/
6.3 通过代码屏蔽(内联注释)
官方文档:内联选项
Luacheck 支持在 Lua 代码中使用 -- luacheck: 注释指令控制检查行为。内联选项优先级最高,会覆盖配置文件和命令行参数。
行级忽略
local unused_var = "temporary" -- luacheck: ignore
忽略特定警告代码
local unused_var = "temporary" -- luacheck: ignore 211
忽略该行所有警告
-- luacheck: ignore
local unused1 = 1
local unused2 = 2
范围忽略(push/pop)
-- luacheck: push
local unused1 = 1
local unused2 = 2
-- luacheck: pop
-- luacheck: push和-- luacheck: pop之间的所有代码的警告都会被忽略。push/pop 必须成对出现。
按警告类型范围忽略
-- luacheck: push ignore 211
local unused = 1
-- luacheck: pop
添加全局变量声明
-- luacheck: globals my_global_var
my_global_var = "hello"
-- luacheck: read_globals my_readonly_var
print(my_readonly_var)
-- luacheck: not_globals unwanted_var
设置标准库
-- luacheck: std ngx_lua
ngx.say("Hello from OpenResty")
文件顶部全局选项
放在文件顶部(无代码的行上)的选项影响整个文件:
-- luacheck: globals g1 g2, ignore 211
local foo = g1(g2) -- 不会产生 111 警告
相关工具推荐
- StyLua -- Lua 代码格式化工具,与 Luacheck 互补形成完整的 Lua 代码质量工具链
- Pre-commit -- 通用 Git hook 框架,可用于集成 Luacheck 到提交前检查流程
- Gitleaks -- 密钥检测工具,适合作为 Lua 项目的安全门禁补充