PMD 自定义规则实践入门样例

article/2025/9/30 21:01:47

原文:https://testerhome.com/topics/4918

准备工作

首先在PMD官网下载最新版本的文件,目前最新版本是5.4.1。 
下载pmd-bin-5.4.1.zip和pmd-src-5.4.1.zip之后解压备用。 
pmd-src-5.4.1是PMD源码包,是无法直接执行的。 
pmd-bin-5.4.1是PMD的可执行包。

目录简介

  • pmd-bin-5.4.1【PMD可执行版本】
    • bin
      • designer.bat【界面工具,能将java源代码转化为AST(抽象语法树),个人推荐使用】
      • bgastviewer.bat【界面工具,与designer.bat功能相似】
      • cpd.bat【用来查找重复代码的工具,命令行版】
      • cpdgui.bat【用来查找重复代码的工具,GUI版】
      • pmd.bat【Window平台下运行PMD需要使用的文件】
      • run.sh【Linux平台下运行PMD需要使用的文件】
    • lib【该目录存放PMD运行依赖的jar包,包括第三方jar包和各种语言的模块jar包】

  • pmd-src-5.4.1【PMD源代码版本】
    • pmd-core【PMD的核心执行调度模块】
    • pmd-java 【针对java语言的检测模块】
      • src ->main
        • java -> net -> sourceforge -> pmd -> lang->java【目录太深,在此处聚合】
        • rule 【该目录下存放已经编写好的java规则文件】
          • basic【基础类规则】
          • AvoidBranchingStatementAsLastInLoopRule.java【避免在循环的最后使用分支语句】
          • AvoidMultipleUnaryOperatorsRule.java【避免一元运算符的多重使用】
          • ...【其他基础类的规则文件】
          • codesize【代码体积类规则】
          • ...【各种规则类别的目录,包含该类别的java编写的规则文件】
      • resources
        • rulesets【java规则对应的xml文件】
          • java
          • android.xml【PMD运行时使用该文件会调用安卓类规则进行扫描】
          • basic.xml【PMD运行时使用该文件会调用基础类规则进行扫描】
          • ...【其他类别的规则xml文件】
      • etc
        • grammar
          • Java.jjt【AST抽象语法树生成所需的语法文件】
    • pmd-java8 【新增对java1.8版本的支持模块】
    • pmd-javascript 【针对javascript语言的检测模块】
    • pmd-jsp 【针对jsp语言的检测模块】
    • ...【其余的主要是针对不同语言实现的独立的检测模块】

自定义规则实现思路

  1. 明确想要自定义的规则。
  2. 列举会触犯这种规则的所有不同的写法。
  3. 使用designer.bat分析所有写法的抽象语法树的特点。
  4. 编写规则代码捕捉这种特点。
  5. 创建自己的xml规则文件,内容包括规则的相关信息。
  6. 运行PMD扫描错误代码,验证是否能触发自定义规则。

下面以一个比较简单的规则举例,详细的阐述一下实现这个规则的具体步骤,帮助大家快速上手。
目前PMD支持两种编写规则的方法:
1. 使用Java进行编写
2. 使用XPath表达式
我首先选择第一种Java编写方式进行讲解。


1. 明确想要自定义的规则

需要自定义的规则:While循环必须使用括号,While循环没有括号很容易困惑代码结构。所以下面以“While循环必须使用括号”这条规则为例。

2. 列举会触犯这种规则的所有不同的写法

写出问题样例的代码写法。

class Example {void bar() {while (baz)buz.doSomething();}
}

弄清楚样例代码是什么样子的,就成功了一半。

3. 使用designer.bat分析所有写法的抽象语法树的特点

PMD扫描时并不是直接使用源码;它使用JavaCC生成解析器来解析源代码并生成AST(抽象语法树)。你可以使用PMD自带的designer工具进行解析代码。
该工具所在目录:pmd-bin-5.4.1/bin/designer.bat
双击designer.bat后出现一个界面,在Source code中填入源代码,点击Go按钮:

这里写图片描述

以上样例代码解析成抽象语法树后如下:

CompilationUnitTypeDeclarationClassDeclaration:(package private)UnmodifiedClassDeclaration(Example)ClassBodyClassBodyDeclarationMethodDeclaration:(package private)ResultTypeMethodDeclarator(bar)FormalParametersBlockBlockStatementStatementWhileStatementExpressionPrimaryExpressionPrimaryPrefixName:bazStatementStatementExpression:nullPrimaryExpressionPrimaryPrefixName:buz.doSomethingPrimarySuffixArguments

图片中Abstract Syntax Tree/XPath/Symbol Table的位置就是抽象后的树形结构,这个树形结构和源代码是有对应关系的。
其中我们需要重点关注的WhileStatement的抽象树结构如下:

WhileStatementExpressionStatementStatementExpression

这个是错误的代码示例的抽象树结构,如果While循环加上了括号,抽象树的结构就会变成:

WhileStatementExpressionStatementBlockBlockStatementStatementStatementExpression

这下能明显的看到了比之前多处了BlockBlockStatement这两个节点。
这样我们只需要写一个规则检查WhileStatement下没有Block节点,只有Statement节点时,就可以报警告知这里是有问题的。
顺便提一句,所有的结构信息,比如一个Statement节点后面可能跟着一个Block节点,这些都是在EBNF grammar中定义的。比如在这个语法定义中,一个Statement的定义是这样的:

void Statement() :
{}
{LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement()
| LOOKAHEAD(2) LabeledStatement()
| Block()
| EmptyStatement()
| StatementExpression() ";"
| SwitchStatement()
| IfStatement()
| WhileStatement()
| DoStatement()
| ForStatement()
| BreakStatement()
| ContinueStatement()
| ReturnStatement()
| ThrowStatement()
| SynchronizedStatement()
| TryStatement()
}

以上代码列出了一个Statement节点后面所有的可能的节点类型。

4. 编写规则代码捕捉这种特点

写一个新的Java类继承net.sourceforge.pmd.lang.java.rule.AbstractJavaRule

import net.sourceforge.pmd.lang.java.rule.*;
public class WhileLoopsMustUseBracesRule extends AbstractJavaRule {
}

PMD工作原理就是在生成的抽象语法树中递归的遍历,直到找出要找的目标,然后返回结果。
接下来我们的目标就是在抽象语法树中找出WhileStatement节点下不存在Statement/Block这种结构的情况。

import net.sourceforge.pmd.lang.ast.*;
import net.sourceforge.pmd.lang.java.ast.*;
import net.sourceforge.pmd.lang.java.rule.*;public class WhileLoopsMustUseBracesRule extends AbstractJavaRule {public Object visit(ASTWhileStatement node, Object data) {Node firstStmt = node.jjtGetChild(1);if (!hasBlockAsFirstChild(firstStmt)) {addViolation(data, node);}return super.visit(node,data);}private boolean hasBlockAsFirstChild(Node node) {return (node.jjtGetNumChildren() != 0 && (node.jjtGetChild(0) instanceof ASTBlock));}
}

这段代码的主要意思:
1. 访问文件中的ASTWhileStatement节点
2. 获取ASTWhileStatement节点下第二个子节点
3. 判断第二个子节点的第一个子节点是不是ASTBlock节点
4. 如果不是ASTBlock节点,说明我们的目标实现,触犯规则
5. 使用addViolation(data, node);语句记录触犯该规则的节点相关数据

5. 创建自己的xml规则文件,内容包括规则的相关信息

现在规则已经写完了,我们需要告诉PMD运行时执行这条规则,就得将这个规则文件的相关信息放在XML规则集文件中。例如:pmd-java/src/main/resources/rulesets/java/basic.xml;这里面有很多规则的定义,复制粘贴一下,改成一个新的规则集文件,名字自己随便取:mycustomrules.xml,自己填充一下元素和属性。
name - WhileLoopsMustUseBracesRule
message - Use braces for while loops
class - 放哪都行. 注意,没有必要放在net.sourceforge.pmd目录下,可以放在com.yourcompany.util.pmd 
description - Use braces for while loops
example - 通过代码片段展示违反的规则样例

<?xml version="1.0"?>
<ruleset name="My custom rules"xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"><rule name="WhileLoopsMustUseBracesRule"message="Avoid using 'while' statements without curly braces"class="WhileLoopsMustUseBracesRule"><description>Avoid using 'while' statements without using curly braces</description><priority>3</priority><example>
<![CDATA[public void doSomething() {while (true)x++;}
]]></example></rule>
</ruleset>

6. 运行PMD扫描错误代码,验证是否能触发自定义规则

在执行前需要把你修改后的pmd-java重新打包:
在命令行中进入pmd-src-5.4.1\pmd-java目录中,执行mvn clean package
打包成功后,将pmd-src-5.4.1\pmd-java\target中的pmd-java-5.4.1.jar替换pmd-bin-5.4.1\lib目录中对应的jar包。
最后在pmd-bin-5.4.1\bin目录中执行
pmd.bat -d c:\path\to\my\src -f xml -R c:\path\to\mycustomrules.xml
可在命令行界面中查看结果。

这里写图片描述

成功!使用Java编写的自定义规则完成!

##使用XPath表达式编写该规则
PMD是支持XPath引擎的,这条“While循环必须使用括号”也可以使用XPath表达式实现。
//WhileStatement[not(Statement/Block)]
意思是匹配查找整个抽象语法树中WhileStatement节点下不存在Statement/Block这种结构的情况。
XPath表达式完成后,不需要写java代码,只写一个xml规则文件就行了。

<?xml version="1.0"?>
<ruleset name="My XPathRule rules"xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"><rule  name="WhileLoopsMustUseBracesRule"language="java"message="Avoid using 'while' statements without curly braces"class="net.sourceforge.pmd.lang.rule.XPathRule"><description>Avoid using 'while' statements without using curly braces</description><properties><property name="xpath"><value>
<![CDATA[
//WhileStatement[not(Statement/Block)]
]]></value></property></properties><priority>3</priority><example>
<![CDATA[
class Example {void bar() {while (baz)buz.doSomething();}
}
]]></example>
</rule>
</ruleset>

运行时指向这个新编写的xml,查看结果:

这里写图片描述

成功!
小技巧:PMD自带的designer.bat工具可以快速生成一个xpath rule xml。
1. 打开designer界面工具,输入源代码,输入XPath表达式,点击Go按钮,确认右下方的结果输出正确。
2. 点击左上方Actions->Create rule XML
3. 在新的页面输入Rule name,Rule msg,Rule desc后,点击Create rule XML按钮,查看输出的结果。
注意:目前版本的designer有一个小BUG,需要自己在XML中的rule标签中指定被测代码的属性language="java"

这篇文章只是教大家快速的上手自定义PMD规则,下一篇文章将重点分析复杂规则如何编写,敬请期待。

参考文献

PMD site. How to write a PMD rule
ONJava.com.Custom PMD Rules
CSDN.静态分析工具PMD使用说明


http://chatgpt.dhexx.cn/article/pSsAI6tk.shtml

相关文章

java pmd 插件下载_sonar-pmd插件集成p3c-pmd

基于官方插件项目sonar-pmd进行改造&#xff0c;这篇文章有详细说明&#xff0c;这个工程有低版本的实现。 每条规则对应的3个配置文件&#xff1a; src\main\resources\org\sonar\l10n\pmd.properties src\main\resources\org\sonar\plugins\pmd\rules.xml src\main\resources…

java pmd eclipse_eclipse插件之Findbugs、Checkstyle、PMD安装及使用

eclipse插件之Findbugs、Checkstyle、PMD安装及使用 一、什么是Findbugs、checkstyle、PMD Findbugs、checkstyle和PMD都可以作为插件插入eclipse&#xff0c;当然也有单独的工具可以实现他们的功能&#xff0c;比如Findbugs Tool就可以不必插入eclipse就可以使用。 三者的功能…

pmd 相机 系统标定

在图像测量过程以及机器视觉应用中&#xff0c;为确定空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系&#xff0c;必须建立摄像机成像的几何模型,这些几何模型参数就是摄像机参数。在大多数条件下这些参数必须通过实验与计算才能得到&#xff0c;这个求解参数…

DPDK — Userspace PMD 源码分析

目录 文章目录 目录PMD driver 通过 IGB_UIO 与 UIO 进行交互注册一个 UIO 设备PMD 的应用层实现Interrupt DPDK&#xff08;中断模式&#xff09; PMD driver 通过 IGB_UIO 与 UIO 进行交互 IGB_UIO 内核模块的另一个主要功能就是让用于态的 PMD 网卡驱动程序得以与 UIO 进行…

java pmd 安装_PMD-Java代码静态分析工具使用

如今&#xff0c;使用代码分析工具来代替人工进行代码审查&#xff0c;已经是大势所趋了。用于Java代码检测的工具中&#xff0c;不乏许许多多的佼佼者&#xff0c;其中PMD就是其中一款。PMD既可以独立运行&#xff0c;也可以以命令行的形式运行&#xff0c;还可以作为插件在ID…

java pmd 安装_PMD的安装及使用

PMD是一种开源分析Java代码错误的工具。 与其他分析工具不同的是&#xff0c;PMD通过静态分析获知代码错误。也就是说&#xff0c;在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则&#xff0c;利用这些规则可以找出Java源程序的许多问题。此外&#xff0c;…

java pmd 安装_4. PMD 使用,编译和自定义规则

一 PMD简介 PMD是一款代码静态检查工具,可以检查出很多代码中潜在的bug以及让人感到疑惑的代码,具体大家可以百度下。 二 PMD源代码下载 下载地址: 需要注意的是注意选择branch,一般选择最新的branch;然后可以用git clone下来,或者直接下载zip压缩包。 如下: 从上图也可…

java pmd 插件下载_pmd eclipse插件

PMD是Eclipse上的一款源代码分析插件&#xff0c;与其他分析工具不同的是&#xff0c;PMD通过静态分析获知代码错误。也就是说&#xff0c;它可以在不运行Java程序的情况下报告错误。pmd 支持Java、JavaScript、XML、XSL等&#xff0c;欢迎下载&#xff01; Eclipse PMD插件更新…

java pmd checkstyle_提高代码质量 CheckStyle FindBugs PMD

注&#xff1a;这是一篇翻译文章&#xff0c;原文&#xff1a;How to improve quality and syntax of your Android code&#xff0c;为了理解连贯&#xff0c;翻译过程中我修改了一些陈述逻辑和顺序&#xff0c;同时也加了一些自己的补充。 在这片文章中&#xff0c;我将从工具…

【C语言】 C语言图形编程 俄罗斯方块 课程设计

程序简介 由纯C语言实现的俄罗斯方块小程序&#xff0c;代码长度700行&#xff0c;使用Turbo C图形库美化了界面&#xff0c;并具俄罗斯方块游戏的所有基本功能。玩家可以通过键盘的“上下左右”键移动“方块”&#xff0c;“空格”去翻转方块&#xff0c;每当方块可以将一行“…

简单c语言图形程序设计,c语言实现一些简单图形的打印

1 #define _CRT_SECURE_NO_WARNINGS 1 因为笔者采用的是VS的编译环境所以有了上面的这一句话 我们都知道平面图形是由一条条线段构成,所以我们就先实现线段的打印 1 //打印自定义长度的线段 2 #include 3 intmain() 4 {5 int i = 0; 6 intn; 7 while (~scanf("%d",&…

C语言图形化编程 【二】

C语言图形编程 二 3 基本贴图3.1 声明一个存储图片的变量3.2 图片的路径3.3 显示图片3.4 透明贴图 4 鼠标操作4.1 声明一个存储鼠标信息的变量4.2 获取鼠标4.3 分类讨论鼠标消息的来源 3 基本贴图 3.1 声明一个存储图片的变量 格式: IMAGE img; //类型 变量名(你要贴的图片的…

基于C语言的图形化编程软件,图形化编程工具

原标题:图形化编程工具 1.产品介绍 唯众图形化编程工具是一款基于拖拽式图形化设计的可视化编程工具库,通过拖拽式图形化编程完成程序设计。作为一种易于掌握的图像化编程环境,是编程初学者学习和掌握程序设计方法的有力工具。用图形化编程方式去理解程序语言,可以让学生更…

C语言:编程打印图形

题目 编程打印以下图形: 代码 #include "stdio.h"void main() {char ch = A;int i,j;for(i=

c语言图形时钟编程,c语言程序+图形编程——打造简易的时钟

全程代码小编就在这里发出来了哈,最终的效果图, // c语言+图形编程 电脑时钟 //包含头文件 #include #include #include void Draw_Dial();//绘制静态的表盘 void Draw_Hand(int hour, int minute, int secend); //绘制表针 //主函数 int main() {initgraph

C语言图形编程--俄罗斯方块制作(一)详解

效果图 用C语言实现俄罗斯方块&#xff0c;需要先解决下面几个问题&#xff1a; 1、如何用C语言绘制图形界面 EasyX图形库(http://www.easyx.cn)即TC的图形库在VC下的移植。 包含库#include <graphics.h> 先初始化图形窗口 initgraph(WINDOW_WIDTH, WINDOW_HIGH) ;WINDOW…

C语言图形代码:三角、金字塔、圣诞树、爱心

在C语言的学习过程中&#xff0c;我们熟练掌握循环以后就可以使用循环编写&#xff0c;我们喜欢的图形代码啦&#xff01; 下面我向大家分别展示四种使用C语言循环编写的代码。 后两种都可以用来给自己的女朋友展示喔 1.三角形 2.金字塔 3.圣诞树 4.爱心 &#xff08;1&#…

linux下c语言图形界面实现,「分享」C语言如何编写图形界面

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 贴吧内经常有人问C语言是不是只能用于字符终端界面开发,不能用于图形界面。大家也都有回答,需要其他的库。MFC,GTK,QT。 本人近期刚用GTK库加上纯C写成了第一个LINUX实用程序。现在与大家分享: 主界面程序gmaxtrix.c #includ…

c语言图形时钟编程,c语言+图形编程——打造浅易的时钟

全程代码小编就在这里发出来了哈 // c语言图形编程 电脑时钟 //包罗头文件 #include #include #include #define PI 3.141592654 void Draw_Dial();//绘制静态的表盘 void Draw_Hand(int hour, int minute, int secend); //绘制表针 //主函数 int main() { initgraph(640, 4…

简单c语言图形程序设计,c语言简单图形编程

c语言编程如何实现图形化? 如果你是说编写用户界面的C语言编程,那就应该学习平台编程.主流平台有windows,linux等. 楼主是领会到C得要点了.C不像JAVA和C#,它们才叫编写应用程序,因为它们的库直接可以编写出程序的应用部分(比如用户界面,调用系统资源等). 但是C语言不能叫做 c语…