资讯动态

PMD 标准规则编写指南:命名、消息与文档规范实战

发布时间:2026/10/15 0:28:03 来源:尧图企业网站定制
静态分析代码质量【免费下载链接】pmdAn extensible multilanguage static code analyzer.项目地址https://gitcode.com/gh_mirrors/pm/pmd点击查看免费下载导读本文是 PMD 官方为**纳入标准发行版standard distribution**的规则制定的开发规范面向想要向 PMD 提交新规则或重构既有规则的贡献者。读完本文你将掌握 PMD 规则在命名、违规消息、规则描述与示例注释上的具体要求理解以底层问题而非实现方式命名的核心理念并能依据规则描述模板写出评审友好、可长期维护的规则文档。文中的正反示例均可在当前仓库的规则定义文件中找到实际对应方便对照学习。[!NOTE] 需要说明的是这套指南是 2021 年6.38.0新引入的目前大部分存量规则尚未完全遵循目标是最终所有规则都按此标准更新。因此本文既是新规则的编写规范也是既有规则重构的参考清单。为什么需要这套指南在原文档rule_guidelines.md中PMD 团队明确了两点动机防止低质量贡献prevent low quality contributions通过事先约定标准避免提交者凭个人风格写出难以评审、难以维护的规则减少规则评审时间reduce time reviewing rules有了统一的命名与文档要求维护者可以更快地评估一条规则是否值得合并。同时指南有明确的作用范围只适用于纳入标准发行版stock PMD的规则。社区自用的自定义规则不受约束但如果希望规则被官方接受、随 PMD 一起分发就必须满足下面的准入要求。标准规则的准入要求要成为 PMD 标准发行版中的一条规则需要同时满足四点广泛适用性Broad applicability规则可以针对某个特定框架但该框架必须是广泛使用的——冷门框架专属的规则不会被采纳扎实的文档Solid documentation文档质量有明确底线具体模板见下文规则描述模板一节性能规则必须附带扎实的基准测试solid benchmarks如果你提交的是性能类规则必须用可复现的基准数据证明其收益且不接受微优化规则no micro-optimization rules与其他规则无重叠No overlap with other rules新规则不得和现有规则检测同一类问题否则会造成重复告警和规则集混乱。这四条在仓库中也有印证PMD 的规则按语言分门别类地定义在各语言的category/*.xml中如 bestpractices.xml、errorprone.xml每条规则都有since引入版本、priority优先级、message和example字段——扎实文档正是由这些字段共同支撑的。规则命名的 Do/Dont命名是原文档着墨最多、也最能体现 PMD 规则设计哲学的部分。核心原则一句话规则名应命名违规所暴露出的底层问题而不是当前检测手段。Dont不要把实现放进名字把实现细节写进规则名一旦规则检测范围演进名字就会说谎而且改名会造成巨大的兼容性成本。原文档给了两个经典反例SwitchStmtShouldHaveDefault在枚举enum成为 Java 一等公民后switch 枚举分支不再必须有 default只要分支覆盖所有枚举常量就算穷尽exhaustive。此时这条规则的名字已经与事实不符——它检测的其实是switch 不穷尽这一更一般的问题MissingBreakInSwitch名字暗示它是通过数 break 数量来判断 fall-through 的但实际上它检测的是switch 分支隐式贯穿fall-through这一行为。因为名字把检测手段写死了团队无法在不改名的情况下改变实现。这两个反例在仓库中都有真实落点SwitchStmtsShouldHaveDefault已被标记为deprecated并重定向到NonExhaustiveSwitch见 bestpractices.xml 中的rule nameSwitchStmtsShouldHaveDefault deprecatedtrue refNonExhaustiveSwitch/MissingBreakInSwitch则是在 PMD 6.37.0 改名为ImplicitSwitchFallThrough规则描述中明确写了这一改名记录见 errorprone.xml。Do命名底层问题好的命名应当直接点出问题本身再用描述和示例解释它为什么是问题、如何修复用NonExhaustiveSwitchStatement替代SwitchStmtShouldHaveDefault名字直接表达switch 不穷尽这一事实修复方式补 default、补分支或未来其他手段留给描述展开用SwitchCaseFallsThrough替代MissingBreakInSwitch直接描述case 分支贯穿这一违规行为。实际落地时PMD 选择了NonExhaustiveSwitch作为最终规则名其 XPath 实现也恰好体现了不依赖单一路径的设计详见下文源码佐证rule nameNonExhaustiveSwitch since1.0 messageSwitch statements or expressions should be exhaustive, add a default case (or missing enum branches) classnet.sourceforge.pmd.lang.rule.xpath.XPathRule description Switch statements should be exhaustive, to make their control flow easier to follow. This can be achieved by adding a default case, or, if the switch is on an enum type, by ensuring there is one switch branch for each enum constant. This rule doesnt consider Switch Statements, that use Pattern Matching, since for these the compiler already ensures that all cases are covered. The same is true for Switch Expressions, which are also not considered by this rule. /description priority3/priority properties property namexpath value![CDATA[ //SwitchStatement (: exclude empty switches :) [count(*) 1] [DefaultCase false()] [ExhaustiveEnumSwitch false()] (: exclude pattern tests - for these, the compiler will ensure exhaustiveness :) [not(*/SwitchLabel[PatternLabel true()])] ]]/value /property /properties ... /rule注意其中用 XPath 注释(: ... :)逐行解释了每个条件的意图——这正是原文档要注释你的 XPath 表达式要求的活范例。Dont为同一问题创建多条规则原文档指出EmptyIfStmt和EmptyWhileStmt本质是同一个问题语法树中存在无用空的语法结构。把它们拆成两条规则只会让规则集膨胀、用户困惑。这一点 PMD 已经给出了终极解法在 6.46.0 引入了EmptyControlStatement用一条规则统一检测空try/finally/switch/synchronized/if/各类循环/初始化器/用作语句的块并明确声明它取代了 EmptyFinallyBlock、EmptyIfStmt、EmptyInitializer、EmptyStatementBlock、EmptySwitchStatements、EmptySynchronizedBlock、EmptyTryBlock、EmptyWhileStmt 共八条旧规则见 codestyle.xml。规则定义中的注释甚至记录了命名过程的取舍——为什么不用EmptyCodeBlock、EmptyStatement、EmptyCodeConstruct——这正是命名要反复推敲的又一佐证。Dont把名字局限在当前能力范围内UnusedPrivateField是原文档给出的反例真正的问题是存在未使用的字段private只是当前检测能力的边界。如果哪天 PMD 具备检测包私有package-private未使用字段的能力名字叫UnusedField就能平滑扩展而UnusedPrivateField则不得不改名。仓库中这条规则的实际描述也印证了其能力边界在演进自 PMD 6.50.0 起带注解的字段或带注解的类中的私有字段不再报告因为注解常被 DI、Mock、Lombok 等框架通过反射使用静态分析无法追踪见 bestpractices.xml 中UnusedPrivateField的描述。能力边界在变名字更要留出余地。规则消息的 Do/Dont违规消息message是用户在报告中第一眼看到的内容直接影响体验。三条原则Do中性指出问题或需要复查的结构。例如Unnecessary parentheses不必要的括号——陈述事实不带情绪、不下指令Dont使用命令式口吻。例如Avoid unnecessary parentheses——除非给出理由否则避免 xxx只会让人反感仓库中大量存量规则的 message 仍以 Avoid 开头如UnusedPrivateField的Avoid unused private fields such as {0}.、UnusedLocalVariable的Avoid unused local variables such as {0}.这正是存量规则尚未完全遵循新指南的直观体现也说明新规则应避免再犯Dont写同义反复tautological的消息。例如Unnecessary parentheses should be removed——读者看到只会反问是啊所以呢。消息应当补充信息量而不是复述问题本身。可以对照NonExhaustiveSwitch的消息写法——它不只是说switch 不穷尽还给出了修复方向add a default case (or missing enum branches)信息密度明显更高。描述、示例与注释要求Do规则描述使用 Markdown 格式并在合理位置按约 80 个字符换行保证在命令行、网页和源码三种场景下都有良好可读性。上文的NonExhaustiveSwitch描述就是范例Do为规则示例写详尽的注释让读者一眼看清该看哪里、哪里是违规、哪里是修复后。仓库里ImplicitSwitchFallThrough的示例堪称范本public void bar(int status) { switch(status) { case CANCELLED: doCancelled(); // break; hm, should this be commented out? case NEW: doNew(); // is this really a fall-through? // what happens if you add another case after this one? case REMOVED: doRemoved(); // fallthrough - this comment just clarifies that you want a fallthrough case OTHER: // empty case - this is interpreted as an intentional fall-through case ERROR: doErrorHandling(); break; } }这个示例见 errorprone.xml 中ImplicitSwitchFallThrough不仅演示了违规与合法写法还借助注释把为什么这是问题新增 case 后行为不可预期、如何合法贯穿// fallthrough注释和哪些 case 自动豁免空 case 视为有意贯穿都交代清楚了——注释本身就是规则文档的一部分Do注释 XPath 表达式。XPath 规则的可读性全靠注释NonExhaustiveSwitch中每行谓词前的(: ... :)注释就是规范要求下的产物。规则描述模板Rule description template原文档给出了标准规则描述必须遵循的六段式结构这是扎实文档的具体定义一句话概要规则报告什么What the rule reports一行说清存在理由与适用场景为什么要有这条规则、在哪些场景有用包括自哪个语言版本起适用等上下文空行分隔理由与假设假设与关键词定义解释上文中使用的所有假设和关键词。例如被覆写的方法会被忽略、就本规则而言可见字段指非私有字段——读者必须能在不读实现的情况下精确理解规则的判定边界已知局限如实描述规则的检测盲区known limitations避免用户误信全量覆盖空行每个属性的用途说明逐个解释规则属性property如何修改上述假设、为什么要用。原文档特别强调如果你解释不了它为什么存在那它就不该存在注意第 4 点对关键词定义的强调与NonExhaustiveSwitch的实际描述完全一致——规则描述中专门界定了本规则不考虑使用模式匹配的 switch 语句与 switch 表达式因为编译器已保证其穷尽性这就是明确假设与边界的规范写法。规则的属性定义同样如此例如LongVariable规则的minimum属性带有min1 max100与默认值17及完整用途描述见 codestyle.xml保证使用者无需读源码即可配置。源码级佐证穷尽性判断到底怎么实现NonExhaustiveSwitch的 XPath 用到了两个 AST 属性DefaultCase与ExhaustiveEnumSwitch它们的真实语义定义在 ASTSwitchLike.java 中isExhaustiveEnumSwitch()当 switch 的测试表达式类型可解析为枚举时比较枚举常量总数与所有分支标签的子节点总数两者相等即为穷尽类型无法解析时返回false对应 XPath 谓词[ExhaustiveEnumSwitch false()]会命中这类无法证明穷尽的 switchisExhaustive()更一般化的判断处理了模式匹配有 type pattern 且无 default 时编译器已保证穷尽、sealed 类型与布尔类型Java 23 预览 JEP 455等更现代的穷尽性场景——这正是规则能力会随语言演进命名要留余地的底层体现。规则并非只有定义文件每个标准规则都有配套的规则测试。NonExhaustiveSwitch的测试类 NonExhaustiveSwitchTest.java 继承PmdRuleTst实际的测试用例写在 XML 数据文件中NonExhaustiveSwitch.xml每个test-code声明expected-problems期望命中数与代码片段例如无 default 的 switch →expected-problems1违规空 switch →expected-problems0不违规注释说明空 switch 由EmptyControlStatement负责带 default 的 switch →expected-problems0合法枚举 switch 未覆盖全部常量 →expected-problems1覆盖全部常量 →expected-problems0。这套XML 定义规则 XML 驱动测试的机制意味着遵循本文指南的规则天然可被 CI 验证——新规则的每个行为声明描述、示例、假设背后都有可执行用例背书。想深入了解规则开发的完整流程可以继续阅读 writing_pmd_rules.md 及其分册Writing XPath Rules、Defining Properties、Testing your Rules。小结提交前的自检清单综合原文档与仓库实践提交一条标准规则前请逐项确认检查项要求仓库对照广泛适用性通用问题或广泛使用的框架专属问题—性能规则有扎实基准拒绝微优化—规则重叠与现有规则检测问题不重复EmptyControlStatement 合并八条空语句规则规则命名命名底层问题不含实现、不限当前能力NonExhaustiveSwitch 替代SwitchStmtsShouldHaveDefault违规消息中性、非命令式、非同义反复对照UnusedPrivateField的旧式 Avoid... 写法描述与示例Markdown、80 字符换行、示例详注、XPath 注释ImplicitSwitchFallThrough示例描述模板概要 → 理由 → 假设与关键词 → 局限 → 属性说明NonExhaustiveSwitch描述测试提供覆盖各分支的 XML 测试用例NonExhaustiveSwitch.xml这套指南的本质是让规则从一段能跑的逻辑升格为一份可评审、可继承、可长期演进的工程资产——命名负责面向未来消息负责面向用户文档负责面向维护者测试负责面向回归。新规则从第一天起就按这个标准写存量规则则按此清单逐步重构最终使整个标准规则库保持一致的品质基线。赞分享静态分析代码质量【免费下载链接】pmdAn extensible multilanguage static code analyzer.项目地址https://gitcode.com/gh_mirrors/pm/pmd点击查看免费下载相关推荐Trigger.dev 文档编写规范基于 Mintlify MDX 的写作规则与实战指南Trigger.dev 文档编写规范基于 Mintlify MDX 的写作规则与实战指南 本文围绕 Trigger.dev 开源仓库中的 .claude/ruAI Agent后端任务调度开发工具可观测性AI 应用文档标题文档标题 概述 简要说明文档目的和范围 功能特性 功能点1详细描述 功能点2详细描述 安装指南 系统要求 Windows版本要求 硬件要求 安装步骤 1.桌面应用系统编程markdownlint规则开发最佳实践命名规范、文档编写、测试覆盖终极指南markdownlint规则开发最佳实践命名规范、文档编写、测试覆盖终极指南 markdownlint作为Node.js生态中功能强大的Markdown/Co开发工具代码质量Lint静态分析上一篇gte-large-zh-openmind vs 主流中文嵌入模型66.72分CMTEB成绩背后的真相下一篇如何用SmolLM实现经济高效的AI推理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑