如何使用PMD自定义规则

准备工作

首先在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-src-5.4.1中除了pmd-core是PMD的核心执行调度模块,其他文件夹都是各种语言检查规则的模块。

其中pmd-bin-5.4.1\lib目录中是执行所依赖的jar包。

pmd-bin-5.4.1\bin目录中文件介绍:

pmd.batrun.sh分别是在window和linux平台下运行用文件。

使用示例:

C:\tmp\pmd-bin-5.4.1\pmd\bin>pmd -d c:\data\pmd\pmd\test-data\Unused1.java -f xml -R rulesets/java/unusedcode.xml
<?xml version="1.0"?><pmd>
<file name="c:\data\pmd\pmd\test-data\Unused1.java">
<violation line="5" rule="UnusedLocalVariable">
Avoid unused local variables such as ‘fr‘
</violation>
</file></pmd>

bgastviewer.batdesigner.bat是能将源代码转化为AST(抽象语法树)的界面工具,其中designer.bat比较常用。

cpd.batcpdgui.bat是查找重复代码的工具(CPD:Copy/Paste Detector)。

自定义规则实现思路

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

下面以一个比较简单的规则举例,详细的阐述一下实现这个规则的具体步骤。

Java 或 XPath?

这里有两种编写规则的方法:

1. 使用Java进行编写

2. 使用XPath表达式

想明白你想要寻找什么

让我们找出我们想定位的问题。下面以“While循环必须使用括号”这条规则为例,以下代码就是问题样例的代码。没有括号很容易困惑代码结构。

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

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

写一个测试数据的例子,查看AST

PMD扫描时并不是直接使用源码;它使用JavaCC生成解析器来解析源代码并生成AST(抽象语法树)。以上代码解析成抽象语法树后如下:

CompilationUnit
 TypeDeclaration
  ClassDeclaration:(package private)
   UnmodifiedClassDeclaration(Example)
    ClassBody
     ClassBodyDeclaration
      MethodDeclaration:(package private)
       ResultType
       MethodDeclarator(bar)
        FormalParameters
       Block
        BlockStatement
         Statement
          WhileStatement
           Expression
            PrimaryExpression
             PrimaryPrefix
              Name:baz
           Statement
            StatementExpression:null
             PrimaryExpression
              PrimaryPrefix
               Name:buz.doSomething
              PrimarySuffix
               Arguments

你可以使用PMD自带的designer工具进行解析代码。

该工具所在目录:pmd-bin-5.4.1/bin/designer.bat

双击designer.bat后出现一个界面,在Source code中填入源代码,点击Go按钮:

图片中Abstract Syntax Tree/XPath/Symbol Table的位置就是抽象后的树形结构,这个树形结构和源代码是有对应关系的。

其中我们需要重点关注的WhileStatement的抽象树结构如下:

WhileStatement
 Expression
 Statement
  StatementExpression

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

WhileStatement
 Expression
 Statement
  Block
   BlockStatement
    Statement
     StatementExpression

哈哈!这下能明显的看到了比之前多处了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后面所有的可能。

写一个规则类

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

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

PMD工作原理就是在生成的抽象语法树中递归的遍历,直到找出要找的目标,然后返回结果。

接下来我们的目标就是在抽象语法树中找出WhileStatement节点:

import net.sourceforge.pmd.lang.java.rule.*;
import net.sourceforge.pmd.lang.java.ast.*;
public class WhileLoopsMustUseBracesRule extends AbstractJavaRule {
    public Object visit(ASTWhileStatement node, Object data) {
        System.out.println("hello world");
        return data;
    }
}

打印输出”hello world”的时候就是我们定义的规则执行了的时候。

把WhileLoopsMustUseBracesRule规则放在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>

用PMD执行你的新规则

pmd.bat -d c:\path\to\my\src -f xml -R c:\path\to\mycustomrules.xml

你会看到之前的“hello world”在命令行中输出。

创建RuleViolation

想要你的检查结果在Report中展示,需要创建RuleViolation

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));
    }
}

使用这个文件再次执行

pmd.bat -d c:\path\to\my\src -f xml -R c:\path\to\mycustomrules.xml

可在命令行界面中查看结果。

参考文献

PMD site. How to write a PMD rule

时间: 2024-08-28 08:35:06

如何使用PMD自定义规则的相关文章

1. PMD 使用,编译和自定义规则

一 PMD简介 PMD是一款代码静态检查工具,可以检查出很多代码中潜在的bug以及让人感到疑惑的代码,具体大家可以百度下. 二 PMD源代码下载 下载地址: https://github.com/pmd/pmd/tree/pmd/5.5.x 需要注意的是注意选择branch,一般选择最新的branch:然后可以用git clone下来,或者直接下载zip压缩包. 如下: 从上图也可以看到,pmd支持的语言有很多,java的检测那就是在pmd-java里面. 三 maven下载和环境变量配置 参考

StyleCop学习笔记——自定义规则

本文将简单的一步一步的指导这可能有助于学习如何创建自己的规则 1.创建一个项目. Visual Studio创建一个新的类库项目.NET3.5 2.引用两个DLL,StyleCop.dll和StyleCop.Csharp.dll. 3.添加自定义的规则. MyCustomAnalyzer.cs代码如下: using StyleCop; using StyleCop.CSharp; namespace MyCustomRules { /// <summary> /// Custom analyz

【猪猪-后端】WebMagic框架搭建的爬虫,根据自定义规则,直接抓取,使用灵活,Demo部署即可查看。

原文:[猪猪-后端]WebMagic框架搭建的爬虫,根据自定义规则,直接抓取,使用灵活,Demo部署即可查看. 源代码下载地址:http://www.zuidaima.com/share/1581523414404096.htm 如果要使用注解方式实现,也是支持的. @TargetUrl("http://my.oschina.net/flashsword/blog/\\d+") public class OschinaBlog { @ExtractBy("//title&qu

yii 框架 自定义规则客户端验证

前提:yii 自定义规则不能通过失去焦点验证 view层中:设置form的3个属性,validationUrl 可以不设置,默认为当前页面,但是一般情况验证不会跟提交数据在一个方法中处理 $form = zActiveForm::begin([ 'id'=> 'validate', 'enableAjaxValidation'=> true, 'validationUrl' => \yii\helpers\Url::toRoute('/hotel/hotel-room/validate-

AWS Config 自定义规则

此过程将引导您完成自定义规则的创建过程,该规则可以评估您的各个 EC2 实例是否为 t2.micro 类型.AWS Config 将针对此规则运行基于事件的评估,这意味着 AWS Config 每次检测到实例配置更改时,都会检查您的实例配置.AWS Config 会将 t2.micro 实例标记为合规实例,并将其他所有实例标记为不合规实例.合规性状态将显示在 AWS Config 控制台中. 为保证这一程序的最佳效果,您的 AWS 账户应该拥有一个或多个 EC2 实例.您的实例中应包含至少一个

Python使用Mistune对markdown自定义规则解析

Mistune--更快的markdown解析器 在Python中有很多markdown解析器,以前我一直使用的是Python-markdown,一个纯Python实现的markdown解析器,别的不说,慢的要死倒是真的.每次点击保存后,都要响应很久,我开始一直以为是我的vps在国外导致的,后来还用了Mistune才知道,不是网速的问题,是解析器的速度问题. 没有对比就没有伤害,Mistune是所有纯Python实现中最快的一个.在纯Python环境中,几乎比Python- markdown快4倍

findbugs自定义规则并配置实现检测

findbugs不过多介绍了,对于这个主题找了一些资料,没有找到一个完整的介绍,要么是介绍怎么写detector,要么就是没有完整的介绍怎么配置生效,下面主要介绍一下怎么配置其生效,至于怎么写这个detector还是有很多资料说明的,不过在些也重复一下. 一.自定义detector 1 ForbidSystemOutClass检测类 package com.test.findbugs; import org.apache.bcel.classfile.Code; import edu.umd.c

jquery.validate自定义规则

// 字符验证 jQuery.validator.addMethod("stringCheck", function(value, element) { return this.optional(element) || /^[\u0391-\uFFE5\w]+$/.test(value); }, "只能包括中文字.英文字母.数字和下划线"); //加点说明.通过addMethod用户可以自定义自己的验证规则 如上面的增加的jQuery.validator.addMe

《写自己的框架6》:自定义规则引擎,适应不断变化的业务场景

规则引擎适于频繁变动做生意的场景规则.我们在应用过程中的业务,还经常要处理大量的业务规则,当然,此外,我们希望有一个规则引擎,支持,这仅仅是更好. 对一些经常使用的商业规则引擎做一下了解,感觉很不错.可是太贵了.看一些开源的引擎吧.也不错,可是感觉相对于我们自己这么简单的需求,太复杂了. 于是就想着自己做个,试试看能不能攻克了自己的这些简单的业务规则频繁变化的业务场景.嗯嗯.脑子里大概过了一下电影,感觉路是通的.主要有例如以下业务需求: 业务规则运行器须要支持多种,也应该支持业务人员自行扩展.原