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 特有的全局变量(如 _KONGkongngx.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,定义了引擎注入的大量只读全局变量(如 ItemStackVoxelAreavector 等),并针对不同子目录设置了自定义全局变量覆盖。配置中忽略了未使用的隐式定义全局变量(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 按以下顺序查找配置文件(优先级从高到低):

  1. CLI 参数 --config 指定的路径
  2. 当前目录的 .luacheckrc
  3. 逐级向上搜索父目录的 .luacheckrc,直到文件系统根目录
  4. 默认配置路径(--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 标准库版本,如 lua54lua53ngx_lualove;支持 +busted 等追加写法
globals string[] 项目自定义可读写全局变量
read_globals string[] 只读全局变量(如 vimngx
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 标准预定义 ngxndk 等全局变量。

-- .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> 设置标准全局变量集合(maxminlua51-lua54luajitngx_lualovebusted 等)
--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> 选择输出格式(defaultplainTAPJUnitvisual_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 配置文件中使用 ignoreexclude_filesinclude_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 项目的安全门禁补充

← 返回目录 > ← 返回总览