介绍
PMD官网:https://pmd.github.io/
文档:https://docs.pmd-code.org/latest/
https://docs.pmd-code.org/latest/pmd_languages_java.html
Java检查规则:https://docs.pmd-code.org/pmd-doc-7.0.0-rc3/pmd_rules_java.html
PMD是一款可扩展的跨语言的静态代码检查工具,它可以发现普通的编程错误,例如未使用的变量、空的catch块、不必要的对象创建等。它支持Java、Apex等10几种编程语言。
它还包含CPD检测器(copy-paste-detector),用于检测代码中的重复代码。
用maven PMD插件扫描生成报告方便,而用eclipse PMD插件可以实时看到结果,修改起来方便。两种是独立的,可以结合起来使用
PMD对Java版本的支持
https://docs.pmd-code.org/latest/pmd_languages_java.html
PMD源码
https://pmd.github.io/
用maven安装、运行
安装PMD
第一次执行maven的pmd:pmd这个goal,就会将maven的PMD插件、连同PMD的版本都下载到maven本地仓库。例如执行后,下载的是PMD 6.55.0版本:
到maven本地仓库中看:
安装Maven PMD 插件
https://maven.apache.org/plugins/maven-pmd-plugin/
Maven PMD 插件允许在maven工程的源代码上自动运行PMD代码分析,生成一个检查结果的site报告,它也支持单独的Copy/Paste Detector tool (即CPD)。
Maven PMD 插件3.21.0版本需要Java 8。支持在运行期间升级PMD。
第一次执行maven的pmd:pmd,就会将maven的PMD插件、连同PMD的版本都下载下来:
可以看到,下载的是maven PMD插件3.21.0版本。
打开maven-pmd-plugin-3.21.0.pom这个文件,看看内容片段:
可以看到,其中指定了对PMD 6.55.0的依赖,所以下载插件的时候,顺便就把PMD的版本下载下来了。
Maven PMD 插件版本和PMD版本之间的关系
https://maven.apache.org/plugins/maven-pmd-plugin/examples/upgrading-PMD-at-runtime.html
Maven PMD 插件使用的Java检查默认规则集
在maven本地仓库中找到Maven PMD 插件的目录:
打开maven-pmd-plugin-3.21.0.jar这个文件,在其中可以找到/rulesets/java/maven-pmd-plugin-default.xml,这个就是Maven PMD 插件使用的Java检查默认规则集:
打开这个文件的内容可以看到,里边只包含了很少一部分规则:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<ruleset name="Default Maven PMD Plugin Ruleset"
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">
<description>
The default ruleset used by the Maven PMD Plugin, when no other ruleset is specified.
It contains the rules of the old (pre PMD 6.0.0) rulesets java-basic, java-empty, java-imports,
java-unnecessary, java-unusedcode.
This ruleset might be used as a starting point for an own customized ruleset [0].
[0] https://pmd.github.io/latest/pmd_userdocs_making_rulesets.html
</description>
<rule ref="category/java/bestpractices.xml/AvoidUsingHardCodedIP" />
<rule ref="category/java/bestpractices.xml/CheckResultSet" />
<rule ref="category/java/bestpractices.xml/PrimitiveWrapperInstantiation" />
<rule ref="category/java/bestpractices.xml/UnusedFormalParameter" />
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable" />
<rule ref="category/java/bestpractices.xml/UnusedPrivateField" />
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod" />
<rule ref="category/java/codestyle.xml/EmptyControlStatement" />
<rule ref="category/java/codestyle.xml/ExtendsObject" />
<rule ref="category/java/codestyle.xml/ForLoopShouldBeWhileLoop" />
<rule ref="category/java/codestyle.xml/TooManyStaticImports" />
<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName" />
<rule ref="category/java/codestyle.xml/UnnecessaryImport" />
<rule ref="category/java/codestyle.xml/UnnecessaryModifier" />
<rule ref="category/java/codestyle.xml/UnnecessaryReturn" />
<rule ref="category/java/codestyle.xml/UnnecessarySemicolon" />
<rule ref="category/java/codestyle.xml/UselessParentheses" />
<rule ref="category/java/codestyle.xml/UselessQualifiedThis" />
<rule ref="category/java/design.xml/CollapsibleIfStatements" />
<rule ref="category/java/design.xml/SimplifiedTernary" />
<rule ref="category/java/design.xml/UselessOverridingMethod" />
<rule ref="category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop" />
<rule ref="category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor" />
<rule ref="category/java/errorprone.xml/AvoidMultipleUnaryOperators" />
<rule ref="category/java/errorprone.xml/AvoidUsingOctalValues" />
<rule ref="category/java/errorprone.xml/BrokenNullCheck" />
<rule ref="category/java/errorprone.xml/CheckSkipResult" />
<rule ref="category/java/errorprone.xml/ClassCastExceptionWithToArray" />
<rule ref="category/java/errorprone.xml/DontUseFloatTypeForLoopIndices" />
<rule ref="category/java/errorprone.xml/EmptyCatchBlock" />
<rule ref="category/java/errorprone.xml/JumbledIncrementer" />
<rule ref="category/java/errorprone.xml/MisplacedNullCheck" />
<rule ref="category/java/errorprone.xml/OverrideBothEqualsAndHashcode" />
<rule ref="category/java/errorprone.xml/ReturnFromFinallyBlock" />
<rule ref="category/java/errorprone.xml/UnconditionalIfStatement" />
<rule ref="category/java/errorprone.xml/UnnecessaryConversionTemporary" />
<rule ref="category/java/errorprone.xml/UnusedNullCheckInEquals" />
<rule ref="category/java/errorprone.xml/UselessOperationOnImmutable" />
<rule ref="category/java/multithreading.xml/AvoidThreadGroup" />
<rule ref="category/java/multithreading.xml/DontCallThreadRun" />
<rule ref="category/java/multithreading.xml/DoubleCheckedLocking" />
<rule ref="category/java/performance.xml/BigIntegerInstantiation" />
</ruleset>
那么,规则集中参考的ref=“category/java/bestpractices.xml/AvoidUsingHardCodedIP” 引用的规则具体来自哪里呢?这个来自PMD版本的压缩包中:
打开pmd-java-6.55.0.jar这个包,可以看到携带的Java检查规则集文件,分了8个大类:
8个大类的规则集文件跟PMD官网中Java规则集正好对应:
https://docs.pmd-code.org/pmd-doc-7.0.0-rc3/pmd_rules_java.html
打开categories.properties文件,内容 如下:
打开bestpractices.xml,看看内容片段:
Maven PMD 插件的goals
https://maven.apache.org/plugins/maven-pmd-plugin/plugin-info.html
pmd:pmd
https://maven.apache.org/plugins/maven-pmd-plugin/pmd-mojo.html
这个goal生成PMD site报告,默认也生成xml格式的报告。
例如,在cmd窗口下执行mvn pmd:pmd:
到target目录下查看内容:
打开pmd.xml文件,里边存放着xml形式呈现的PMD违反项:
下面是自动拷贝过来的规则集:
下面是生成的html形式的报告:
打开报告看看内容:
pmd:aggregate-pmd
https://maven.apache.org/plugins/maven-pmd-plugin/aggregate-pmd-mojo.html
当maven过程中包含几个模块的时候,可以用这个goal生成一个PMD集成报告。这个goal生成PMD site报告,默认也生成xml格式的报告。
例如,在cmd窗口下执行mvn pmd:aggregate-pmd(输出太长,只部分截屏):
到target目录下查看:
自动拷贝过来的规则集文件:
pmd.xml是xml形式的集成报告:
html形式的集成报告:
pmd:cpd
https://maven.apache.org/plugins/maven-pmd-plugin/cpd-mojo.html
用PMD的 Copy/Paste Detector (CPD) 工具生成一个拷贝、粘贴的报告。这个goal生成PMD site报告,默认也生成xml格式的报告。
例如,在cmd下执行mvn pmd:cpd:
到target目录下看看内容:
cpd.xml是xml形式的报告:
html形式的报告:
pmd:aggregate-cpd
https://maven.apache.org/plugins/maven-pmd-plugin/aggregate-cpd-mojo
当maven过程中包含几个模块的时候,可以用这个goal调用PMD的 Copy/Paste Detector (CPD) 工具生成一个拷贝、粘贴的集成报告。这个goal生成PMD site报告,默认也生成xml格式的报告。
例如,在cmd下执行mvn pmd:aggregate-cpd:
到target目录下查看:
xml形式的报告:
html形式的报告:
pmd:check
https://maven.apache.org/plugins/maven-pmd-plugin/check-mojo.html
如果在源代码中发现PMD的违反项就停止构建。在调用自身之前,会先自动调用pmd:pmd。这个goal生成PMD site报告,默认也生成xml格式的报告。
例如,在cmd下执行mvn pmd:check:
到target目录下查看下内容:
xml形式的报告:
html形式的报告:
pmd:aggregate-pmd-check
https://maven.apache.org/plugins/maven-pmd-plugin/aggregate-pmd-check-mojo.html
如果一个工程包含几个模块,执行这个goal的时候,在源代码中发现PMD的违反项就停止构建。在调用自身之前,会先自动调用pmd:aggregate-pmd。这个goal生成PMD site报告,默认也生成xml格式的报告。
例如,在cmd下执行mvn pmd:aggregate-pmd-check(结果很长,只有部分截屏):
到target目录下看看内容:
xml形式的报告:
html形式的报告:
pmd:cpd-check
https://maven.apache.org/plugins/maven-pmd-plugin/cpd-check-mojo.html
执行拷贝、粘贴检查,如果有违反项,就停止构建。在执行这个goal之前,会自动先调用pmd:cpd这个goal。生成xml和html形式的报告。
在cmd下执行mvn pmd:cpd-check:
到target目录下查看内容:
xml形式的报告:
html形式的报告:
pmd:aggregate-cpd-check
https://maven.apache.org/plugins/maven-pmd-plugin/aggregate-cpd-check-mojo.html
如果工程有几个模块,执行拷贝、粘贴集成检查,如果有违反项,就停止构建。在执行这个goal之前,会自动先调用pmd:aggregate-cpd这个goal。生成xml和html形式的报告。
在cmd下执行mvn pmd:aggregate-cpd-check(输出很长,只部分截屏):
到target目录下查看:
xml形式的报告:
html形式的报告:
maven PMD插件引用定制的规则集文件
例如,定制的规则集文件的路径:D:\temp\eclipse-workspace\java_work\config\pmd\java\pmd-java-rules.xml
maven工程的pom文件增加如下配置:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.21.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<rulesets>
<ruleset>D:/temp/eclipse-workspace/java_work/config/pmd/java/pmd-java-rules.xml</ruleset>
</rulesets>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<rulesets>
<ruleset>D:/temp/eclipse-workspace/java_work/config/pmd/java/pmd-java-rules.xml</ruleset>
</rulesets>
</configuration>
</plugin>
</plugins>
</reporting>
eclipse PMD插件安装、运行
安装eclipse PMD插件
进入Eclipse Marketplace:
在搜索框中输入PMD,回车:
点击后面的install按钮:
点击Finish按钮:
安装一会后,弹出如下窗口:
点击Select All按钮:
点击Trust Selected按钮:
安装完成后,弹出如下窗口:
点击Restart Now按钮,重启eclipse。eclipse重启后,点击Window->Preferences菜单:
点击左侧导航栏的PMD,出现如下界面,说明已经安装成功:
右侧窗口中,可以看到PMD违反项每个基本的名字、符号:
右边窗口下边可以看到eclipse PMD插件的版本、PMD的版本:
配置eclipse PMD插件的信息
CPD(拷贝、粘贴检测器)配置
点击Launch CPD按钮:
有多个选项,例如可以选择源文件的根目录、语言是Java或者其它的语言:
Rule Configuraton配置
-
在右侧最上面勾选Use global rule management以后,下面的规则集就可以选上、或者不选。这个设置会覆盖工程特有的选择:
-
在Rules grouped by选择Rule set,可以按照类来分组,共8个大类:
-
点击右面的Import按钮,可以导入外部规则集,跟现在的合并:
- 点击右边的Export按钮,可以将现在的规则集导出到一个文件中:
- 如果规则有属性,在Properties栏会有显示,在下面的Properties这个Tab页,可以设置属性:
在工程上执行PMD检查
鼠标右键点击工程,选择PMD->Check Code:
可以展开:
在下面点击某个违反项,可以在代码中高亮显示:
定制PMD规则集文件
https://docs.pmd-code.org/pmd-doc-6.55.0/pmd_userdocs_making_rulesets.html
https://docs.pmd-code.org/pmd-doc-6.55.0/pmd_userdocs_configuring_rules.html
https://docs.pmd-code.org/pmd-doc-6.55.0/pmd_userdocs_best_practices.html
可以在maven PMD插件默认规则集的基础上定制。
建议每条采用引用单个规则的方式,例如:
前面章节说过,category/java/errorprone.xml/EmptyCatchBlock这样的源在PMD发布包中。
引用单个规则的好处是自己可以完全控制,因为每个规则有很多属性可以利用。
当然,每条也可以采用大块引用的方式(引用了xml文件中的所有规则,但不推荐这种方式),例如:
这种添加方式是简单、快捷,但自己不能完全控制,PMD以后的版本可能增加、或者减少规则,默认都会被引用进来,而自己可能还不知情。
可以把定制的规则集文件放到某个目录下面,被引用。例如:
D:/temp/eclipse-workspace/java_work/config/pmd/java/pmd-java-rules.xml