KurtWagner/zlinter

GitHub: KurtWagner/zlinter

一款从源码集成到 build.zig 的可扩展 Zig 代码检查工具,帮助开发者在构建阶段自动发现代码风格和潜在问题。

Stars: 84 | Forks: 6

Zlinter icon # Zlinter - Zig 的 Linter [![Zig 支持](https://img.shields.io/badge/Zig-0.14.x%20%7C%200.15.x%20%7C%200.16.x%20%7C%20master-%23f3ab20?logo=zig&style=flat)](http://github.com/kurtwagner/what-the-zig) [![linux](https://img.shields.io/github/actions/workflow/status/KurtWagner/zlinter/linux.yml?branch=master&label=linux&style=flat)](https://github.com/KurtWagner/zlinter/actions/workflows/linux.yml) [![windows](https://img.shields.io/github/actions/workflow/status/KurtWagner/zlinter/windows.yml?branch=master&label=windows&style=flat)](https://github.com/KurtWagner/zlinter/actions/workflows/windows.yml) [![覆盖率状态](https://img.shields.io/coveralls/github/KurtWagner/zlinter/master?style=flat)](https://coveralls.io/github/KurtWagner/zlinter?branch=master) [![许可证: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat)](https://opensource.org/licenses/MIT) 一个可扩展且可定制的 **Zig linter**(带有 [AST explorer](https://kurtwagner.github.io/zlinter/explorer/)),从源码集成到你的 `build.zig` 中。 **linter** 是一种用来自动检查源代码是否存在风格问题、bug 或可能导致错误的模式的工具,
帮助开发者编写更整洁、更可靠的代码。
![截图](https://static.pigsec.cn/wp-content/uploads/repos/cas/0a/0a91069d7bfc3880d54832aeed4a493e72d734a0c9f7574b9484f47482ca7807.png)
## 目录 - [快速入门](#getting-started) - [自动修复](#autofix) - [自定义规则](#custom-rules) - [内置规则](RULES.md) - [declaration_naming](RULES.md#declaration_naming) - [field_ordering](RULES.md#field_ordering) - [field_naming](RULES.md#field_naming) - [file_naming](RULES.md#file_naming) - [function_naming](RULES.md#function_naming) - [import_ordering](RULES.md#import_ordering) - [max_positional_args](RULES.md#max_positional_args) - [no_comment_out_code](RULES.md#no_comment_out_code) - [no_deprecated](RULES.md#no_deprecated) - [no_empty_block](RULES.md#no_empty_block) - [no_global_vars](RULES.md#no_global_vars) - [no_hidden_allocations](RULES.md#no_hidden_allocations) - [no_inferred_error_unions](RULES.md#no_inferred_error_unions) - [no_literal_args](RULES.md#no_literal_args) - [no_literal_only_bool_expression](RULES.md#no_literal_only_bool_expression) - [no_orelse_unreachable](RULES.md#no_orelse_unreachable) - [no_panic](RULES.md#no_panic) - [no_redundant_comptime](RULES.md#no_redundant_comptime) - [no_swallow_error](RULES.md#no_swallow_error) - [no_todo](RULES.md#no_todo) - [no_unsafe_undefined](RULES.md#no_unsafe_undefined) - [no_unused](RULES.md#no_unused) - [require_braces](RULES.md#require_braces) - [require_exhaustive_enum_switch](RULES.md#require_exhaustive_enum_switch) - [require_fmt](RULES.md#require_fmt) - [require_labeled_continue](RULES.md#require_labeled_continue) - [require_doc_comment](RULES.md#require_doc_comment) - [require_errdefer_dealloc](RULES.md#require_errdefer_dealloc) - [switch_case_ordering](RULES.md#switch_case_ordering) - [配置](#configuration) - [路径](#configure-paths) - [build.zig 中的规则](#configure-rules-in-buildzig) - [按目录配置规则](#configure-rules-by-directory) - [通过注释禁用](#disable-with-comments) - [命令行参数](#command-line-arguments) - [优化](#configure-optimization) - [支持的 zig 版本](#supported-zig-versions) - [背景](#background) - [版本控制](#versioning) - [贡献](CONTRIBUTING.md) - [发布说明](RELEASES.md) ## 快速入门 `zlinter` 不是一个独立的二进制文件——它被内置到你项目的 `build.zig` 中。 这使得它可以灵活地适应每个项目的需求。只需添加依赖项并 将其连接到一个构建步骤,比如 `zig build lint`: **1. 将依赖项保存到你的 zig 项目:** 对于 0.14.x: ``` zig fetch --save git+https://github.com/kurtwagner/zlinter#0.14.x ``` 对于 0.15.x: ``` zig fetch --save git+https://github.com/kurtwagner/zlinter#0.15.x ``` 对于 0.16.x: ``` zig fetch --save git+https://github.com/kurtwagner/zlinter#0.16.x ``` 对于 master (0.17.x-dev): ``` zig fetch --save git+https://github.com/kurtwagner/zlinter#master ``` **2. 在你的 `build.zig` 中配置 `lint` 步骤:** ``` const zlinter = @import("zlinter"); // ... const lint_cmd = b.step("lint", "Lint source code."); lint_cmd.dependOn(step: { // Swap in and out whatever rules you see fit from RULES.md var builder = zlinter.builder(b, .{}); builder.addRule(.{ .builtin = .field_naming }, .{}); builder.addRule(.{ .builtin = .declaration_naming }, .{}); builder.addRule(.{ .builtin = .function_naming }, .{}); builder.addRule(.{ .builtin = .file_naming }, .{}); builder.addRule(.{ .builtin = .switch_case_ordering }, .{}); builder.addRule(.{ .builtin = .no_unused }, .{}); builder.addRule(.{ .builtin = .no_deprecated }, .{}); builder.addRule(.{ .builtin = .no_orelse_unreachable }, .{}); break :step builder.build(); }); ``` **3. 运行 linter:** 请记住,第一次运行会比较慢,因为缓存还没有预热: ``` zig build lint ``` 你也可以指定路径(有关更多选项,请参见[命令行参数](#command-line-arguments)): ``` zig build lint -- --include src/ file.zig ``` ### 替代方案:启用所有内置规则 如果你只是想测试一下 zlinter,你也可以启用所有规则,然后 从命令行选择性地运行规则。很多规则都非常严苛, 所以除了为你的项目测试 zlinter 的规则外,不建议这样做: 1. 在 `build.zig` 中启用所有内置规则 ``` const zlinter = @import("zlinter"); const lint_cmd = b.step("lint", "Lint source code."); lint_cmd.dependOn(step: { var builder = zlinter.builder(b, .{}); inline for (@typeInfo(zlinter.BuiltinLintRule).@"enum".field_values) |field_value| { builder.addRule(.{ .builtin = @enumFromInt(field_value) }, .{}); } break :step builder.build(); }); ``` 1. 选择性地运行规则: ``` zig build lint -- --rule no_unused no_deprecated ``` ## 自动修复 一些 linter 规则支持自动修复某些问题。 例如,假设你的项目配置了这些规则,要自动修复未使用的声明和字段排序问题: ``` # 首先确保你的工作分支是干净的(或者备份你的代码!) $ git status # 然后运行修复命令(你可能需要多次运行) $ zig build lint -- --rule field_ordering --rule no_unused --fix ``` 有时可能需要多次运行才能完全解决所有可修复的问题。即,使用 `--fix` 运行,直到它报告应用了 0 个修复。 ## 自定义规则 可以将定制的规则添加到你的项目中。例如,也许你真的不喜欢 cats,并拒绝在任何标识符中存在任何 `cats`。参见示例规则 [`no_cats`](./integration_tests/src/no_cats.zig),然后像内置规则一样将其集成到你的 `build.zig` 中: ``` builder.addRule(.{ .custom = .{ .name = "no_cats", .path = "src/no_cats.zig", }, }, .{}); ``` 或者,看看 ,这是一个带有 zig 项目的最小自定义规则示例。 ## 配置 ### 配置路径 `build.zig` 中使用的构建器有一个 `addPaths` 方法,可用于 添加包含和排除的文件及目录。例如, ``` builder.addPaths(.{ .include_dirs = &.{ b.path("engine-src"), b.path("src") }, .exclude_dirs = &.{ b.path("src/android") }, .exclude_files = &.{ b.path("engine-src/generated.zig") }, }); ``` 将 lint `engine-src/` 和 `src/` 下的 zig 文件,但不包括 `engine-src/generated.zig` 和 `src/android/` 下的任何 zig 文件。 ### 在 `build.zig` 中配置规则 `addRule` 接受一个匿名结构体,表示要添加的规则的 `Config`。这些是应用的基础配置。例如, ``` builder.addRule(.{ .builtin = .field_naming }, .{ .enum_field = .{ .warning = .snake_case }, .union_field = .off, .struct_field_that_is_type = .{ .@"error" = .title_case }, .struct_field_that_is_fn = .{ .@"error" = .camel_case }, }); builder.addRule(.{ .builtin = .no_deprecated }, .{ .severity = .warning, }); ``` 其中 `Config` 结构体定义在规则源文件 [`no_deprecated.Config`](./src/rules/no_deprecated.zig) 和 [`field_naming.Config`](./src/rules/field_naming.zig) 中。 ### 按目录配置规则 通过在该目录中添加 `zlinter.zon` 文件,可以为该目录及其后代源文件覆盖在 `build.zig` 中配置的规则。例如, ``` // src/lib/zlinter.zon .{ .rules = .{ .field_naming = .{ .enum_field = .off, }, }, } ``` 将为 `src/lib/` 及其下任何目录中的枚举字段关闭 `field_naming`。其他规则配置字段将继续使用 `build.zig` 中的基础配置。 这要求该规则已经在你的 `build.zig` 中启用并配置。 ### 通过注释禁用 #### 禁用下一行 为下一行源代码禁用所有规则或一组明确的规则。 语法: ``` zlinter-disable-next-line [rule_1] [rule_n] [- comment] ``` 例如, ``` // zlinter-disable-next-line no_deprecated - not updating so safe const a = this.is.deprecated(); ``` #### 禁用当前行 为当前行源代码禁用所有规则或一组明确的规则。 语法: ``` zlinter-disable-current-line [rule_1] [rule_n] [- comment] ``` 例如, ``` const a = this.is.deprecated(); // zlinter-disable-current-line ``` #### 禁用多行 为多行源代码禁用所有规则或一组明确的规则。 语法: ``` zlinter-disable [rule_1] [rule_n] [- comment] zlinter-enable [rule_1] [rule_n] [- comment] ``` 例如,为给定的一组规则禁用多行: ``` // zlinter-disable rule_a rule_b - rationale var something = doSomethin(); var something_else = doSomethingElse(); // zlinter-disable rule_a rule_b ``` 例如,为所有规则禁用多行: ``` // zlinter-disable - rationale var something = doSomethin(); var something_else = doSomethingElse(); // zlinter-disable ``` 如果省略 `zlinter-enable`,直到 EOF 的所有行都将被禁用。 ### 命令行参数 ``` zig build lint -- [--include ...] [--exclude ...] [--filter ...] [--rule ...] [--fix] [--quiet] [--max-warnings ] ``` - `--include` 在这些路径上运行 linter,忽略 `build.zig` 中定义的包含和排除项,强制解析并 lint 这些路径(如果它们存在)。 - `--exclude` 将这些路径从 lint 中排除。除非与 `--include` 一起使用,否则此参数将与 `build.zig` 中定义的排除项结合使用。 - `--filter` 用于将运行过滤到一组特定的已解析路径。与 `--include` 不同,这会保持 `build.zig` 中定义的包含和排除项不变。 - `--quiet` 仅报告错误(不报告警告)。 - `--max-warnings` 如果警告数量超过此数值则失败。 - `--fix` 用于自动修复某些问题(例如,移除未使用的容器声明) - **仅当你使用源代码控制系统时才使用此功能,因为它可能导致代码丢失!** 例如 ``` zig build lint -- --include src/ android/ --exclude src/generated.zig --rule no_deprecated no_unused ``` - 将解析 `src/` 和 `android/` 下的所有 zig 文件,但会排除对 `src/generated.zig` 的 lint;并且 - 只会运行规则 `no_deprecated` 和 `no_unused`。 ### 配置优化 `zlinter.builder` 接受 `.optimize`(默认为 `.ReleaseSafe`)。例如, ``` var builder = zlinter.builder(b, .{.optimize = .ReleaseFast }); ``` 如果你的项目很大,可能值得将 optimize 设置为 `.ReleaseFast`。请记住,第一次运行可能会比较慢,因为它要使用新的优化首次构建模块。 从 0.16.x 开始,`.Debug` 的运行速度要慢得多,因为它使用调试分配器。除非你正在开发 zlinter 或自定义规则,否则应避免使用它。 ### 编译单元 大型项目通常有许多具有重叠模块图的编译单元。默认情况下,`zlinter` 首先使用可执行文件,然后是库,接着是测试,然后是目标单元,最后是测试对象。这通常会给 linter 提供你期望的模块/import 上下文,而无需解析构建中的每个编译单元,这样速度较慢。 编译单元用于从你 import 图中的依赖项解析声明。 你可以使用显式选择器覆盖该选择。例如,执行所有可执行文件和一个特定的测试: ``` const exe = b.addExecutable(.{ .name = "my_app", .root_module = app_module, }); const unit_tests = b.addTest(.{ .name = "unit_tests", .root_module = test_module, }); var builder = zlinter.builder(b, .{}); builder.setCompileUnits(&.{ .exe, .{ .explicit = unit_tests }, }); ``` 如果你只想对上下文解析单个可执行文件,而你的项目注册了多个,那么你应该: ``` builder.setCompileUnits(&.{ .{ .explicit = your_exe }, }); ``` 仅当你有意让每个发现的编译单元都提供上下文时才使用 `.all`。对于大型项目来说,它可能会慢得多,并且可能无法提供多少额外的上下文解析。 ## 支持的 zig 版本 计划是支持 `master`(主要是因为这是跟上 zig 变化的一项重要练习)以及最新的前一个版本。 目前,支持 [`0.14.x`](https://github.com/KurtWagner/zlinter/tree/0.14.x)、[`0.15.x`](https://github.com/KurtWagner/zlinter/tree/0.15.x)、[`0.16.x`](https://github.com/KurtWagner/zlinter/tree/0.16.x) 和 [`master`](https://github.com/KurtWagner/zlinter/tree/master)。 如果没有 API 兼容性问题,对规则的修复和改进可能会被 cherry-pick 到旧版本。 一旦 zig 发布 `1.x` 版本,这种情况可能会改变。 ## 背景 编写 `zlinter` 的初衷是在我的个人项目中使用。主要的动机是通过构建步骤从源码集成它,以便它可以 1. 在构建时进行定制(例如,自定义规则);并且 2. 与你项目的源代码控制一起进行版本控制(无需兼顾单独的二进制文件) 我将其开源以防它更具有通用价值,并很乐意让它 围绕需求有机地发展,如果这样做有价值的话。 它使用 `std.zig` 和 `std.Build.Configuration` 来构建和分析 zig 源文件。 ## 版本控制 `zlinter` 将: - 遵循与 `zig` 相同的语义化版本控制; - 为 `zig` `master` 版本发布使用 `master` 分支;并且 - 为 `zig` `0.14.x` 版本发布使用 `0.14.x` 分支。 这可能会改变,特别是当 `zig` 在 `1.x` 处于“稳定”状态时。如果你对此有意见,欢迎在 [#20](https://github.com/KurtWagner/zlinter/issues/20) 上发表评论。
标签:Apache Flink, Redis利用, SOC Prime, Zig, 代码规范检查, 开发工具, 错误基检测, 静态代码分析