扩展Alibaba P3C 实现自定义代码规范检查

P3C (源码地址: https://github.com/alibaba/p3c ): 


        一款代码规范的检查工具,有对应的ide插件,能在编码过程中对设置的规则进行提示,可以针对公司编码规范对它原来基础上做了进一步的拓展;

p3c主要包括3部分:
- PMD实现(p3c-pmd):使用PMD来实现代码规范检查
- Intellij IDEA插件
- Eclipse插件

《阿里巴巴Java开发手册》中的大部分规则都是在p3c-pmd模块中实现的,该部分也是这节研究的主要部分

PMD

        p3c使用了PMD。PMD是一款静态代码扫描工具,该工具可以做到检查Java代码中是否含有未使用的变量、是否含有空的抓取块、是否含有不必要的对象等。PMD使用JavaCC生成解析器来解析源代码并生成AST(抽象语法树),通过对AST的检查可以直接从源代码文本层面来对代码进行检查,在PMD内部称为规则。即是否符合规则指的是,穷举源码各种可能的写法,然后在AST上检查是否出现。而规则的实现,重点便在对AST的处理上

1.1 pmd-bin-5.4.1【PMD可执行版本】 (https://pmd.github.io/)

- 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包】


1.2. AST

 关于AST的介绍网上有很多,可以直接搜索,这里重要提两点:

- AST是源代码的抽象语法结构的树状表示
- 抽象语法树并不依赖于原语言的语法,也就是说同语法分析阶段所采用的上下文无关

 PMD使用JavaCC来生成AST。关于JavaCC也可以在网上查看相关资料,这里不多介绍,只要知道JavaCC是一个词法分析生成器和语法分析生成器便行。
1.3. 自定义规则

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

        自定义规则:  方法参数不能超过5个,如果参数无法减少,可以将多个参数封装成一个对象

  • 2. 列举会触犯这种规则的所有不同的写法。
public void fn(int a, int b, int c,int d, int f, int g) {
        dosomething();
    }

 

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

注意: 这个树形结构和源代码是有对应关系的。其中我们需要重点关注的 `FormalParameters ` 的抽象树结构如下:注意标红的节点,根据定义的方法参数,`FormalParameter`这个节点会对应的增加或减少,这样我们只需要写一个规则检查 `FormalParameters` 下的 `FormalParameter ` 节点是否大于5就可以了,就可以报警告知这里是有问题的。

具体详细的节点的信息可以看对应的jar文件

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

        代码规范实现的主要模块,使用pmd来实现。p3c-pmd模块在代码组织上很工整,可以按照相同的模式增加自定义的规则/规则集。对于本文需求,打算在该模块的基础上增加一个extend模块,用于实现自定义规则集。如下,为对应的源码路径好规则集路径


具体代码实现

public class MethodParamsNumRule extends AbstractAliRule {

    private static final int PARAMSNUM = 5;

    @Override
    public Object visit(ASTFormalParameters node, Object data) {
        if (node.jjtGetNumChildren()>PARAMSNUM) {
            addViolationWithMessage(data,node,"java.extend.MethodParamsNumRule.rule.msg");
        };
        return super.visit(node, data);
    }

}

这段代码意思:
1. 访问文件中的 `ASTFormalParameters` 节点
2. 获取 `ASTFormalParameters` 节点下所有的子节点
3. 判断子节点的数量是否大于5
4. 如果是,说明我们的目标实现,触犯规则
5. 使用 `addViolationWithMessage(data, node,message);` 语句记录触犯该规则的节点相关数据
    注意:
        1:类  `MethodParamsNumRule ` 继承自  `com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule` ,AbstractAliRule继承自AbstractJavaRule,重写了setDescription,setMessage和addViolationWithMessage等方法,这里提到的3个方法,增加了多语言支持。
        2:addViolationWithMessage()方法中的node参数是你触犯规则的具体的代码,切记不要写上一级或者是方法级的节点,这样会造成误报;
        3:p3c-pmd使用Resource Bundle来提供多语言支持。每个消息都有一个唯一id来对应,p3c-pmd通过重写方法,将方法参数映射为消息的id,以统一消息的配置。如下为本地对应的消息提示内容:
        <entry key="java.extend.StringSplitRule.rule.msg">
            <![CDATA[ 云充吧: 使用String.split(String regex)时, 注意regex是否是正则表达式 ]]>
        </entry>

 

 

  • 5. 创建自己的xml规则文件,内容包括规则的相关信息。   
现在规则已经写完了,我们需要告诉PMD运行时执行这条规则,就得将这个规则文件的相关信息放在XML规则集文件中。例如: `pmd-java/src/main/resources/rulesets/java/extend.xml` ;这里面有很多规则的定义,复制粘贴一下,改成一个新的规则集文件,名字自己随便取: `MethodParamsNumRule.xml` ,自己填充一下元素和属性。
        name - MethodParamsNumRule
        message - java.extend.MethodParamsNumRule.rule.msg
        class - com.alibaba.p3c.pmd.lang.java.rule.extend.MethodParamsNumRul  放哪都行. 注意,没有必要放在 `net.sourceforge.pmd` 目录下,可以放在 `com.yourcompany.util.pmd` 
        description - 具体描述信息
        example - 通过代码片段展示违反的规则样例

 

   <!-- 方法的参数 -->
   <rule name="MethodParamsNumRule"
         language="java"
         message="java.extend.MethodParamsNumRule.rule.msg"
         class="com.alibaba.p3c.pmd.lang.java.rule.extend.MethodParamsNumRule">
       <priority>2</priority>
       <example>
           <![CDATA[
   public class Example {
 public void fn(int a, int b, int c,int d, int f, int g) {
     dosomething();
 }
}
  ]]>
       </example>
   </rule>

 

 

  • 6: 测试规则
PMD推荐对于每个规则,至少要有一个正向和逆向的测试用例,来验证规则出现和不出现的情况。对于规则的测试,PMD也提供了一套框架,只要按照约定好的方式添加xml测试文件即可。
 PMD约定了几个规则,用来加载测试案例

- 测试类要继承  `net.sourceforge.pmd.testframework.SimpleAggregatorTst类,该整合了Junt,可以在里面增加需要的测试方法。
- 对于在  `src/test/resource` 和测试类对应的路径下增加一个xml目录,在增加同第一步同名的xml文件,该文件用于书写测试集。


例子:

规则实现类路径如下:
 net.sourceforge.pmd.lang.java.rule.extend.EntityNullRuleTest
测试案例集如下:src/test/resources/net/sourceforge/pmd/lang/java/rule/extend/xml/MethodParamsNumRule.xml

按照规则建出文件进行测试,


 

  • 7: 本地 mvn install 

        测试通过,已经完成了自定义规则的实现,现在就是要把该内容应用到ide上了。首先,需要将该模块进行编译,这里直接保存到本地maven参考,好在本地调试。 直接将p3c-pmd的版本升级为2.0.1,然后执行mvn install,可以在本地仓库看到对应的版本

  • 8:buildPlugin (本案例选用的是idea-plugin);

        idea-plugin主要实现了idea的插件,能够对代码进行实时检查。这里涉及到idea自定义插件的开发,这里就不深入了,网上有很多教程。这里只介绍如何将上面自定义的规则接入该模块。
注意: 配置gradle对应的版本, 本次pmd 使用的是gradle-4.4,高版本可能会build失败

allprojects {
    group 'com.alibaba.p3c.idea'
    apply plugin: 'java'
    apply plugin: 'kotlin'
    apply plugin: 'maven-publish'

    sourceCompatibility = 1.8
    compileJava.options.encoding = 'UTF-8'
    configurations.all {
        resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
    }
    repositories {
        mavenLocal() //注意
        jcenter()
        mavenCentral()
    }

    dependencies {
        compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
        testCompile group: 'junit', name: 'junit', version: '4.11'
    }
}


        1.修改idea-plugin模块的build.gradle文件,开启本地仓库配置,以便从本地直接加载最新的p3c-pmd依赖。
        如上,增加了 `mavenLocal()` 
        2.修改p3c-common的build.gradle,更改p3c-pmd的版本为2.0.1
        3.修改p3c-common模块resources/rulesets/java/ali=pmd.xml,增加`<rule ref="rulesets/java/ali-extend.xml"/>` 
        以增加自定义规则检查。
        4.在p3c-common模块下,执行 `gradle clean buildPlugin` ,生成对应的插件。

  • 9. 验证

        本地安装该插件,可以得到如下效果


                        


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值