Clippy 开发提案机制详解:Roadmap 2021 与语法树模式(Syntax Tree Patterns)
2026/9/15 17:57:03 网站建设 项目流程

Clippy 开发提案机制详解:Roadmap 2021 与语法树模式(Syntax Tree Patterns)

【免费下载链接】rust-clippyA bunch of lints to catch common mistakes and improve your Rust code. Book: https://doc.rust-lang.org/clippy/项目地址: https://gitcode.com/GitHub_Trending/ru/rust-clippy

在 Clippy 的开发文档体系中,book/src/development/proposals/README.md承担着一个特殊的角色:它专门收集那些"着眼于长远、需要较大工作量、最好先有一份正式提案"的改进项目。这类项目不同于单纯地新增一个 lint 或修复一个误报,它们通常涉及用户、开发者与维护者三方体验的整体性提升,往往需要数周甚至数月才能完成。本文以该章节为骨架,完整解读其收录的两份核心提案——Roadmap 2021(Clippy 首个年度路线图)与Syntax Tree Patterns(基于声明式模式语法重写 lint 匹配逻辑的 RFC 级设计),并结合当前仓库的源码实现,说明这些提案中的设想在今天的 Clippy 中落地到了什么程度。读完本文,你将理解 Clippy 团队如何为"大改动"立项、如何设定优先级,以及 lint 匹配逻辑从"命令式嵌套 if"走向"声明式模式"的完整设计思路。

一、Proposals 章节的定位与组织结构

book/src/development/proposals/README.md全文虽短,却精准定义了该章节的两个边界条件:

  • 面向长期项目:它只收录"accepted proposals for changes that should be worked on in or around Clippy in the long run",即已被接受的、值得长期推进的变更提案;
  • 覆盖三个层次:除了持续新增 lint 和优化既有 lint,Clippy 同样关心用户(users)、开发者(contributors)与维护者(maintainers)的体验改进。凡是这类"bigger picture"项目,先写提案再动手,方便后续工作中随时引用。

在 Clippy Book 的导航树(book/src/SUMMARY.md)中,该章节位于Development → Proposals下,与 基础篇、新增 lint 指南、基础设施 等并列,是贡献者了解 Clippy 中长期方向的第一站。章节目前收录两份提案:

  1. Roadmap 2021——Clippy 的第一份年度路线图,规划用户侧与内部侧的改进方向;
  2. Syntax Tree Patterns——2019 年提出的 RFC(对应 PR #3875),主张引入类正则的声明式语法树模式语言来编写 lint。

二、提案一:Roadmap 2021——Clippy 的首份年度路线图

book/src/development/proposals/roadmap-2021.md是 Clippy 团队在 2021 年制定的第一份正式路线图。文档开宗明义:它只回答"What?"(做什么),不回答"How?"(怎么做),具体的执行细节由后续的 tracking issue 和指派的团队成员负责。

2.1 背景与动机

随着 Rust 语言与生态持续增长,Clippy 的用户和贡献者越来越多。这带来三方面的挑战:

  • 关于可靠性(reliability)与易用性(usability)的 issue 不断涌现;
  • 小团队的 issue/PR 流量难以消化;
  • 由于缺乏流程或团队成员时间不足,较大的项目常常无法完成。

同时,[Rust Roadmap 2021] 要求每个团队都定义清晰、跨团队统一的流程,这份路线图正是 Clippy 对该要求的回应。

2.2 用户侧计划(User Facing)

2.2.1 易用性(Usability)

cargo check之后无输出:当时cargo check之后再运行cargo clippy,clippy 不产生任何输出。随着rust-analyzer的普及(它依赖cargo check检查代码),这个问题的影响被放大。相关的收尾工作还包括稳定cargo clippy --fix命令、在rustfix中支持 multi-span suggestions(对应 issue #4612)。

lints.toml配置:社区反复提出需要一个可复用的配置文件来定义 lint 级别。文档给出的结论是:与 cargo 团队协作,编写 RFC 并落实这样一个配置文件(关联 issue #3164、cargo#5034 与 IRLO 讨论)。从当前仓库看,这一方向的成果体现在 Clippy 丰富的clippy.toml配置体系上——book/src/lint_configuration.md列出了上百个配置项(如allow-dbg-in-testscognitive-complexity-thresholdmsrv等),均由clippy_config/src/conf.rs解析并在clippy_config/src/types.rs中定义类型,配置与 lint 的对应关系由元数据测试tests/config-metadata.rs校验。

Lint 分组(Lint Groups):随着管理 lint 的 issue 增多,文档提出两条路径:引入更多 lint 分组让用户能更好地管理 lint,或改进 lint 分类流程以减少因误报(false positives, FPs)而禁用 lint 的情况。文档特别强调:Clippy 的 lint 比rustc的 lint 更激进(less conservative),这一点未来不会改变(关联 issue #5537、#6366)。当前仓库中declare_clippy_lintclippy_lints/src/declared_lints.rs定义的分类体系(style、correctness、suspicious、complexity、perf、pedantic、restriction、cargo、nursery 等)正是该设计的延续,cargo dev new_lint--category参数(clippy_dev/src/main.rs)直接枚举了这些分组。

2.2.2 可靠性(Reliability)

误报率(False Positive Rate):最坏情况下,新 lint 只在 nightly 停留两周就会进入 beta 乃至 stable,而如今使用 nightly Rust 的人更少,导致带大量误报的 lint 更容易进入 stable——用户要么禁用新 lint,要么干脆放弃 Clippy。路线图要求开发并实施一套流程来阻止这种情况(issue #6429)。在今天的仓库中,lintcheck正是这一设想的落地:lintcheck/会拉取一组真实 crates 并运行 Clippy,把结果与基准对比,从而在真实代码上发现误报与回归;测试源清单位于lintcheck/lintcheck_crates.tomllintcheck/ci_crates.toml

2.3 内部计划(Internal)

2020 年底的数据是 Clippy 拥有超过 1000 个 open issues,且有 25–35 个 open PR 长期徘徊。这既是项目受欢迎的证明,也意味着团队成员工作量加大、贡献者等待 review 的时间变长。

2.3.1 团队管理(Management)
  • 明确团队成员期望:按照 Rust Roadmap 2021 的要求,产出说明"成为团队成员意味着什么"的文档,降低招募门槛;
  • 扩大团队规模:制定加入团队的流程文档,允许团队中存在不同角色(如 triage 与 review 分工),提高团队在成员暂时离开时的稳定性;
  • 定期会议:引入每两周一次的同步会议(尤其在 Rust 版本同步之前),为异步沟通补充定期的同步渠道;
  • Triage 流程:官方虽声明遵循 Rust 的 triage 流程,但当时无人执行。文档建议跨项目共享 triage 团队,或实现仪表盘/工具来简化 triage。
2.3.2 开发(Development)
  • 新 lint 与既有 lint 的流程:由于错误 lint 进入 stable 的概率较高,需要建立 lint 分类流程,并开发测试系统定位真实代码中表现不佳的 lint(关联 #6429 评论);
  • 流程规范化:建立重大变更的提议与讨论流程,明确"何时默认启用/禁用某个 lint";
  • Dev-Tools:扩展cargo dev(issue #5394)。当前仓库中的clippy_dev/src/main.rs展示了这套工具链的现状:cargo dev bless(自动更新.stderr/.fixed测试基线)、cargo dev dogfood(用 Clippy 检查自身)、cargo dev fmtcargo dev update_lints(同步 lint 注册信息)、cargo dev new_lintcargo dev lint(对任意文件/包运行 Clippy)、cargo dev rename_lintcargo dev deprecatecargo dev uplift(将 lint 上交给 rustc)以及cargo dev sync update_nightlycargo dev release bump_version等;
  • 贡献者指南:将仓库中的doc目录升级为mdbook——也就是今天这套 Clippy Book 的雏形;
  • rustc集成:Clippy 已通过git subtree集成进rust-lang/rust仓库,文档列出三个待改进点:与 rustc 使用相同的rustfmt版本与配置;让cargo dev在 Rust 仓库中同样可用(如cargo dev blesscargo dev update_lintscargo dev deprecate);简化 subtree 同步流程。当前仓库中完整的双向同步过程记录在 同步文档:每两周在 Rust stable 发布日之后进行(首次执行于 2020-08-27),git subtree push将 rust 仓库中的 Clippy 拷贝同步回本仓库,再通过cargo dev sync update_nightly升级rust-toolchain.toml中的 nightly 版本。

2.4 优先级(Prioritization)

路线图给出的优先级结论是:

  1. 控制 warn/deny-by-default lint 的误报率拥有最高优先级;
  2. 其他用户侧问题也应获得高优先级,但不能妨碍内部问题的解决;
  3. 会议、tracking issue、文档等基础内部流程应尽快建立,因为它们是管理用户侧项目的前提。

2.5 参考与反思(Prior Art / Drawbacks)

文档援引 Rust 自身的路线图流程(由 RFC 1728 于 2016 年确立)作为先例,并坦承这份路线图"相当大",2021 年内未必能完成所有条目——因此把未完成项留给 2022 路线图复审,而不是强行收缩范围。这种"先立方向、允许延期、定期复审"的节奏,也是 Clippy 处理长期项目的默认姿态。

三、提案二:Syntax Tree Patterns——用声明式模式语言编写 lint

如果说 Roadmap 2021 回答的是"Clipy 往哪里走",那么book/src/development/proposals/syntax-tree-patterns.md回答的则是"lint 应该怎么写"这一底层方法论问题。该提案启动于 2019-03-12,RFC PR 编号 #3875。

3.1 动机:两个核心痛点

痛点一:手写嵌套匹配难以阅读。在语法树(AST、HIR)上查找满足特定性质的节点是写 lint 的主要工作,非平凡 lint 往往需要嵌套的模式匹配。例如判断"表达式是布尔字面量"要写:

if let ast::ExprKind::Lit(lit) = &expr.node { if let ast::LitKind::Bool(_) = &lit.node { ... } }

collapsible_iflint 的匹配逻辑(简化版)更是层层嵌套:

if let ast::ExprKind::If(check, then, None) = &expr.node { if then.stmts.len() == 1 { if let ast::StmtKind::Expr(inner) | ast::StmtKind::Semi(inner) = &then.stmts[0].node { if let ast::ExprKind::If(check_inner, content, None) = &inner.node { ... } } } }

if_chain!宏压平后依然晦涩:

if_chain! { if let ast::ExprKind::If(check, then, None) = &expr.node; if then.stmts.len() == 1; if let ast::StmtKind::Expr(inner) | ast::StmtKind::Semi(inner) = &then.stmts[0].node; if let ast::ExprKind::If(check_inner, content, None) = &inner.node; then { ... } }

这类代码"解释起来容易、读起来难",命令式风格描述的是"如何匹配",而不是声明式地指定"要匹配什么"。因此提案的第一个目标是简化 lint 的编写与阅读

痛点二:强依赖编译器内部数据结构。Clippy lint 直接面向编译器的 AST/HIR 编写,编译器对这些结构的任何小改动都可能破坏大量 lint。提案的第二个目标是让 lint 摆脱对编译器 AST/HIR 数据结构的直接依赖

(值得一提的是,collapsible_if在今天仍是 Clippy 的核心 lint 之一,其实现位于 clippy_lints/src/collapsible_if.rs,配置项lint-commented-code等控制其行为,见book/src/lint_configuration.md;它同时被 tests/ui/collapsible_if/ 等测试用例覆盖。)

3.2 总体思路:类正则的层级模式语言

提案借鉴正则表达式的思想——用受限的领域专用语言(DSL)描述搜索模式,让实现去做实际匹配。但正则适合扁平字符序列,无法直接应用于语法树这样的层级结构,因此提案设计了一套受正则启发、面向层级语法树的匹配系统。

3.3 模式语法(Pattern Syntax)

提案引入pattern!宏定义命名模式,例如匹配值为false的布尔字面量:

pattern!{ my_pattern: Expr = Lit(Bool(false)) }

宏展开为一个函数my_pattern,接受语法树表达式,返回Option表示是否匹配。使用方式:

impl EarlyLintPass for MyAwesomeLint { fn check_expr(&mut self, cx: &EarlyContext, expr: &syntax::ast::Expr) { if my_pattern(expr).is_some() { cx.span_lint( MY_AWESOME_LINT, expr.span, "This is a match for a simple pattern. Well done!", ); } } }

完整的模式语法由以下构件组成:

语法概念说明示例
_Any匹配任意内容(类似正则的*_
<node-name>(<args>)Node匹配某个语法树节点的特定变体Lit(Bool(true))If(_, _, _)
<lit>LiteralRust 字面量,匹配自身'x'false101
<a> \| <b>Alternation备选分支Char(_) \| Bool(_)
()Empty空序列或可选值的None变体Array( () )If(_, _, ())
<a> <b>Sequence序列Tuple( Lit(Bool(_)) Lit(Int(_)) Lit(_) )
<a>*<a>+<a>?<a>{n}<a>{n,m}<a>{n,}Repetition与正则重复语法一致Array( _* )If(_, _, _?)Array( Lit(_){10} )
<a>#<name>Named submatch命名子匹配,供结果提取Lit(Int(_))#fooLit(Int(_#bar))

Any(_:最简单的模式,匹配任何内容:

pattern!{ // matches any expression my_pattern: Expr = _ }

Node(<node-name>(<args>):匹配 AST 节点的特定变体。Lit节点有一个描述字面量类型的参数,If节点有三个参数(条件、then 块、else 块):

pattern!{ // matches any expression that is a boolean literal my_pattern: Expr = Lit(Bool(_)) } pattern!{ // matches if expressions that have a boolean literal in their condition // Note: `_?` means the else branch is optional and can be anything. my_pattern: Expr = If( Lit(Bool(_)) , _, _?) }

Literal(<lit>:Rust 字面量匹配自身:

pattern!{ // matches the boolean literal false my_pattern: Expr = Lit(Bool(false)) } pattern!{ // matches the character literal 'x' my_pattern: Expr = Lit(Char('x')) }

Alternation(a | b:备选分支:

pattern!{ // matches if the literal is a boolean or integer literal my_pattern: Lit = Bool(_) | Int(_) } pattern!{ // matches if the expression is a char literal with value 'x' or 'y' my_pattern: Expr = Lit( Char('x' | 'y') ) }

Empty(():空序列或None变体:

pattern!{ // matches if the expression is an empty array my_pattern: Expr = Array( () ) } pattern!{ // matches if expressions that don't have an else clause my_pattern: Expr = If(_, _, ()) }

Sequence(<a> <b>:连续匹配:

pattern!{ // matches the array [true, false] my_pattern: Expr = Array( Lit(Bool(true)) Lit(Bool(false)) ) }

Repetition(<a>*<a>+<a>?<a>{n}<a>{n,m}<a>{n,}:语法与正则的重复完全一致。文档用一个表格精确区分了If(_, _, _)If(_, _, _?)If(_, _, ())三者在"有无 else 块"上的差异:

模式有 else 块无 else 块
If(_, _, _)匹配不匹配
If(_, _, _?)匹配匹配
If(_, _, ())不匹配匹配

Named submatch(<a>#<name>:命名子匹配有三种绑定位置(字面量、字符、表达式):

pattern!{ // matches character literals and gives the literal the name foo my_pattern: Expr = Lit(Char(_)#foo) } pattern!{ // matches character literals and gives the char the name bar my_pattern: Expr = Lit(Char(_#bar)) } pattern!{ // matches character literals and gives the expression the name baz my_pattern: Expr = Lit(Char(_))#baz }

3.4 结果类型(The Result Type)

很多 lint 需要的检查超出模式语法本身能表达的范围(例如判断节点是否来自宏展开、节点上方是否有注释、两个节点的值是否相同)。提案的方案是:给模式中的子表达式命名,匹配时返回所有被命名的子节点引用——类似正则的捕获组(capture groups)。

给定如下模式:

pattern!{ my_pattern: Expr = Lit(Char(_#val_inner)#val)#val_outer }

可以这样访问结果:

if let Some(result) = my_pattern(expr) { result.val_inner // type: &char result.val // type: &syntax::ast::Lit result.val_outer // type: &syntax::ast::Expr }

结果结构体中的字段类型由模式决定:

  • 命名在重复子模式上时是向量,例如Array( Lit(_)*#foo )result.foo类型为Vec<&syntax::ast::Expr>
  • 命名只出现在备选分支的某一支时是Option,例如Lit( Bool(_#bar) | Int(_) )result.bar类型为Option<&bool>
  • 同一名字出现在类型兼容的多个分支时则是普通引用:Lit(_#baz) | Array( Lit(_#baz) )result.baz类型为&syntax::ast::Lit

命名子匹配采用扁平命名空间(flat namespace),这是有意为之——对大多数 lint 而言,扁平命名比层级命名更易用。

两阶段(Two stages):借助命名子模式,lint 可以分两阶段编写:第一阶段由模式语法完成粗略匹配,第二阶段利用命名引用做附加检查(如断言节点不是宏展开的一部分)。

3.5 参考实现(Reference-level Explanation)

架构总览:模式语法经解析/降级(parsing / lowering)生成PatternTree;PatternTree 与具体语法树的匹配通过IsMatch trait完成,后者针对syntax::astrustc::hirsyn等不同语法树分别实现:

Pattern syntax | | parsing / lowering v PatternTree ^ | IsMatch trait | +---------------+-----------+---------+ | | | | v v v v syntax::ast rustc::hir syn ...

PatternTree:核心数据结构,与 Rust AST/HIR 类似,但有两个关键区别:不包含Span等解析信息;可以表达备选、序列与可选。简化版定义:

pub enum Expr { Lit(Alt<Lit>), Array(Seq<Expr>), Block_(Alt<BlockType>), If(Alt<Expr>, Alt<BlockType>, Opt<Expr>), IfLet(Alt<BlockType>, Opt<Expr>), } pub enum Lit { Char(Alt<char>), Bool(Alt<bool>), Int(Alt<u128>), } pub enum Stmt { Expr(Alt<Expr>), Semi(Alt<Expr>), } pub enum BlockType { Block(Seq<Stmt>), }

配套的容器类型:

pub enum Alt<T> { Any, Elmt(Box<T>), Alt(Box<Self>, Box<Self>), Named(Box<Self>, ...) } pub enum Opt<T> { Any, // anything, but not None Elmt(Box<T>), None, Alt(Box<Self>, Box<Self>), Named(Box<Self>, ...) } pub enum Seq<T> { Any, Empty, Elmt(Box<T>), Repeat(Box<Self>, RepeatRange), Seq(Box<Self>, Box<Self>), Alt(Box<Self>, Box<Self>), Named(Box<Self>, ...) } pub struct RepeatRange { pub start: usize, pub end: Option<usize> // exclusive }

解析 / 降级pattern!宏的输入先解析为 ParseTree,再降级为 PatternTree。合法模式由 PatternTree 定义决定:例如Lit(Bool(_)*)非法(因为Expr::Lit的参数类型是Alt<Lit>,不支持重复),而Array( Lit(_)* )合法(因为Array的参数是Seq<Expr>)。注意模式中的名字对应 PatternTree 枚举的变体(variant)——上例中的LitExpr::Lit,而非Lit枚举本身。

IsMatch Trait:连接 PatternTree 与具体语法树的桥梁:

pub trait IsMatch<O> { fn is_match(&self, other: &'o O) -> bool; }

例如将 PatternTree 的Litast::LitKind匹配的实现(节选):

impl IsMatch<ast::LitKind> for Lit { fn is_match(&self, other: &ast::LitKind) -> bool { match (self, other) { (Lit::Char(i), ast::LitKind::Char(j)) => i.is_match(j), (Lit::Bool(i), ast::LitKind::Bool(j)) => i.is_match(j), (Lit::Int(i), ast::LitKind::Int(j, _)) => i.is_match(j), _ => false, } } }

这一抽象的价值在于:当 AST/HIR 结构变化时,只需更新各IsMatch实现,既有 lint 保持不变——这正是提案"让 lint 独立于编译器数据结构"目标的实现机制。

3.6 权衡与备选方案

性能(Drawbacks/Performance):模式匹配代码当时未做性能优化,可能慢于手写匹配;两阶段方案(先粗匹配、再附加检查)也可能比"结构与属性一次检查"慢。文档给出的缓解方向是"早期过滤"(early filtering,见未来可能性一节),同时强调"看不到任何概念层面的性能限制"。

适用性(Drawbacks/Applicability):预计多数 lint 可以用模式编写,但未必全部都能——可能仍有 lint 需要手写匹配代码,造成代码库内两种风格并存的不一致。文档承认这是一种潜在缺陷。

备选方案:Rust 风格的模式语法:另一种思路是让模式语法接近真实 Rust 语法(类似quote!宏),例如匹配条件为false的 if 可以写作:

if false { #[*] }

但文档列举了该方案的严重问题:

  1. 在已经复杂的 Rust 语法上叠加模式所需的备选、序列、重复、命名子匹配等扩展,会难以阅读、更难解析;
  2. 运算符优先级问题:1 + 0 #[*:BinOpKind] 0中模式通配了任意二元运算符,解析器无法预先知道优先级(1 + 0 + 0(1+0)+0,而1 + 0 * 01+(0*0));
  3. 命名子匹配难以安放:1 #foo中的#foo究竟指intast::Litast::Expr还是ast::Stmt?很多 AST 节点没有可挂名标签的语法元素,只能挂到最外层节点,访问内层节点又要回到手写匹配;
  4. 需要维护一个至少与 Rust 解析器同等复杂的自定义解析器,且未来 Rust 语法变化可能与之不兼容。

结论是:开发这样的语法,是用极大复杂性去解决一个相对小的问题。作为补偿,文档提议开发一个工具:给定一段 Rust 程序,自动生成仅匹配该程序的模式(类似 Clippy 的 author lint)。

3.7 未来可能性(Future Possibilities)

提案文档还规划了模式系统的演进方向:

  • 实现完整的 Rust 语法:当前项目只实现了一小部分语法,未来逐步扩展 PatternTree 与 IsMatch 实现即可支持更多 lint;
  • 早期过滤(Early filtering):允许在匹配过程中尽早求值附加条件,例如:
pattern!{ pat_if_without_else: Expr = If( _, Block( Expr( If(_, _, ())#inner ) | Semi( If(_, _, ())#inner ) )#then, () ) where !in_macro(#then.span); }
  • 反向引用(Backreferences):要求模式多处匹配同一个值,例如assign_op_patterna = a op ba op= b)可写作:
pattern!{ assign_op_pattern: Expr = Assign(_#target, Binary(_, =#target, _) }
  • 匹配后代节点(Match descendant):支持"包含至少两个 return 语句的函数"这类跨直接子节点的模式;
  • 否定操作符:支持Lit(!Bool(_))表达"不是布尔字面量的字面量";
  • 函数式组合:支持定义子模式函数(如expr_or_semiif_or_if_let),消除模式内重复,并可在多个 lint 间共享;
  • Clippy Pattern Author 工具:输入合法 Rust 语法,自动生成恰好匹配它的模式,降低编写模式的起步难度;
  • 支持其他语法:模式系统本身语言无关,为其他语言的 AST 实现新的 PatternTree 与 IsMatch 即可复用;甚至可以为模式语法本身编写 lint(例如把Array( Lit(Bool(false)) Lit(Bool(false)) )建议改为Array( Lit(Bool(false)){2} ))。

四、从提案到现状:如何在当前仓库中跟踪这些议题

如果你希望追踪这些提案在今天的落地情况,可以在仓库中找到如下对应物:

  • 开发工具链cargo dev的完整命令集定义在 clippy_dev/src/main.rs,实现分布在 clippy_dev/src/ 下的dogfood.rsfmt.rsnew_lint.rsedit_lints.rssync.rsrelease.rs等模块;
  • 误报控制与测试系统:lintcheck/ 及其配置清单lintcheck/lintcheck_crates.toml,配合 tests/ui/ 下海量的.rs/.stderr/.fixed测试基线(cargo dev bless负责更新);
  • rustc 集成与同步:同步文档 与rust-toolchain.tomlcargo dev sync update_nightly更新其中的 nightly 版本);
  • 配置体系book/src/lint_configuration.md(由cargo bless --test config-metadata生成)与clippy_config/src/conf.rs
  • Syntax Tree Patterns 的对照实现collapsible_if的现行手写匹配位于 clippy_lints/src/collapsible_if.rs,其测试覆盖在 tests/ui/collapsible_if/——正是提案中反复用作示例的 lint,可用于对比"命令式嵌套匹配"与"声明式模式"两种写法的差异。

五、结语

Clippy 的 Proposals 章节展示了这个项目在"不断新增 lint"之外的自我演进方式:Roadmap 2021 确立了用户侧优先、内部流程先行、误报率第一的治理框架,其中的许多条目(cargo dev工具链、lintcheck 测试系统、subtree 同步、mdbook 文档化)都已在当前仓库中生根发芽;Syntax Tree Patterns 则提出了一套受正则启发、通过 PatternTree 与 IsMatch trait 解耦编译器数据结构的声明式 lint 编写范式,其设计文档完整保留了动机、语法、参考实现与备选方案,是理解"为什么 Clippy 的 lint 匹配逻辑长成这样"的最佳入口。无论你是想为 Clippy 贡献新 lint、加入团队参与治理,还是单纯想读懂 Clippy 的内部架构,这份提案目录都值得从 proposals 章节 读起。

【免费下载链接】rust-clippyA bunch of lints to catch common mistakes and improve your Rust code. Book: https://doc.rust-lang.org/clippy/项目地址: https://gitcode.com/GitHub_Trending/ru/rust-clippy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询