静态代码分析工具广泛用于Java开发,以改进代码库并识别潜在的漏洞和设计缺陷。每个工具都有自己的特点,目的和优势,这有助于提高代码质量。
FindBugs
- 主要用于分析Java字节码,用于查找设计缺陷和潜在错误。
- 需要编译代码才能解决问题,由于工作在字节码级别,所以速度会很快。
- 此工具的主要类别包括:正确性,错误操作,多线程正确性,性能问题,代码漏洞,安全性。
PMD
- 他分析JavaCC生成的抽象语法树,不需要实际编译
- 它识别潜在的问题,主要是无用代码和重复代码,循环的复杂性,过度复杂的表达式以及CheckStyle几乎所有的功能。
Checkstyle
- 主要用来分析源代码,并着眼通过遍历Checkstyle生成的简单AST来改进编码标准
- 它验证源代码的编码约定,如标题,导入,空格,格式等。
现在我们开始在项目中集成,对于每个工具都需要编写相对应的gradle脚本。
findbugs.gradle
apply plugin: 'findbugs'
task findbugs(type: FindBugs) {
description 'Find bugs mainly design flaws, bad practices, multithreaded correctness and code vulnerabilities.'
group 'verification'
excludeFilter = file("$project.rootDir/tools/rules-findbugs.xml")
classes = fileTree("$project.buildDir/intermediates/classes/dev/debug/com/aranoah")
source = fileTree('src/main/java')
effort 'max'
reportLevel = "high"
classpath = files()
reports {
xml.enabled = false
html.enabled = true
html.destination = "$project.buildDir/outputs/findbugs/findbugs.html"
}
}
task: 定义Gradle要执行的任务,这里是findbugs
excludeFilter: 自定义的规则
classes: 要进行分析的字节码
html.destination: 你需要定义生成的报告所存储的位置
rules-findbugs.xml
<FindBugsFilter>
<!-- Do not check auto-generated resources classes -->
<Match>
<Class name="~.*R\$.*"/>
</Match>
<!-- Do not check auto-generated manifest classes -->
<Match>
<Class name="~.*Manifest\$.*"/>
</Match>
<!-- Do not check auto-generated classes (Dagger puts $ into class names) -->
<Match>
<Class name="~.*Dagger*.*"/>
</Match>
<!-- Do not check for non-initialized fields in tests because usually we initialize them in @Before -->
<Match>
<Class name="~.*Test"/>
<Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"
type="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"/>
</Match>
<!-- Ignore UPM in lambdas from Retrolambda, FindBugs does not correctly understand them -->
<Match>
<Bug code="UPM"/>
<Class name="~.*\$\$Lambda\$.*"/>
</Match>
<!-- Ignore Butterknife auto-generated classes -->
<Match>
<Class name="~.*\$\$ViewBinder*"/>
</Match>
<Match>
<Class name="~.*\$\$ViewBinder\$InnerUnbinder*"/>
</Match>
</FindBugsFilter>
同样添加pmd和checkstyle的gradle脚本
pmd.gradle
apply plugin: 'pmd'
task pmd(type: Pmd) {
description 'Identifying potential problems mainly dead code, duplicated code, cyclomatic complexity and overcomplicated expressions'
group 'verification'
ruleSetFiles = files("$project.rootDir/tools/rules-pmd.xml")
source = fileTree('src/main/java')
include '**/*.java'
exclude '**/gen/**'
reports {
xml.enabled = false
html.enabled = true
html.destination = "$project.buildDir/outputs/pmd/pmd.html"
}
}
rules-pmd.xml
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="PMD rules"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>Custom ruleset for 1mg Android application</description>
<exclude-pattern>.*/R.java</exclude-pattern>
<exclude-pattern>.*/gen/.*</exclude-pattern>
<rule ref="rulesets/java/unnecessary.xml"/>
<rule ref="rulesets/java/imports.xml">
<exclude name="TooManyStaticImports"/>
</rule>
<rule ref="rulesets/java/unusedcode.xml"/>
<rule ref="rulesets/java/junit.xml"/>
<rule ref="rulesets/java/logging-java.xml"/>
<rule ref="rulesets/java/braces.xml"/>
<rule ref="rulesets/java/strings.xml"/>
<rule ref="rulesets/java/basic.xml"/>
<rule ref="rulesets/java/design.xml">
<exclude name="ConfusingTernary"/>
</rule>
<rule ref="rulesets/java/typeresolution.xml"/>
<rule ref="rulesets/java/empty.xml/EmptyCatchBlock">
<properties>
<property name="allowCommentedBlocks" value="true"/>
</properties>
</rule>
</ruleset>
checkstyle.gradle
apply plugin: 'checkstyle'
task checkstyle(type: Checkstyle) {
description 'Check code standard'
group 'verification'
configFile file("${project.rootDir}/tools/rules-checkstyle.xml")
source fileTree('src/main/java')
include '**/*.java'
exclude '**/gen/**'
classpath = files()
showViolations true
reports {
xml.enabled = true
html.enabled = true
html.destination = "$project.buildDir/outputs/checkstyle/checkstyle.html"
}
}
请注意这里xml.enabled设置的是true,如前所述,checkstyle对自己生成的AST起作用,因此需要创建树检查器,即xml.enabled设置为false时,会出现下错误:
无法创建检查器:
/Users/ashwini.kumar/GitHub/Druid/app/build/reports/checkstyle/checkstyle.xml
rules-checkstyle.xml
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="error"/>
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<!-- Trailing spaces -->
<module name="RegexpSingleline">
<property name="format" value="\s+$"/>
<property name="message" value="Line has trailing spaces."/>
</module>
<module name="TreeWalker">
<!-- Imports -->
<module name="RedundantImport">
<property name="severity" value="error"/>
</module>
<module name="AvoidStarImport">
<property name="severity" value="error"/>
</module>
<!-- General Code Style -->
<module name="EmptyBlock">
<property name="option" value="TEXT"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<module name="NoFinalizer"/>
<module name="ArrayTypeStyle"/>
<module name="ModifierOrder"/>
<module name="Indentation">
<property name="basicOffset" value="4"/>
<property name="braceAdjustment" value="0"/>
<property name="caseIndent" value="4"/>
<property name="throwsIndent" value="4"/>
<property name="lineWrappingIndentation" value="8"/>
<property name="arrayInitIndent" value="2"/>
</module>
</module>
</module>
所有的gradle脚本和规则都要放到你的项目的根目录下的/tools文件夹下,所有的规则和脚本都在 Github上可以找到。你可能需要配置规则并根据你实际需要以及可以避免的情况编写排除内容,需要完成的最后一件事就是在应用程序gradle文件中定义脚本。
apply from: "$project.rootDir/tools/findbugs.gradle"
apply from: "$project.rootDir/tools/checkstyle.gradle"
apply from: "$project.rootDir/tools/pmd.gradle"
现在所有的地方都已经设置正确了,已经为每个SCA工具编写了自己的规则和gradle脚本,现在要生成报告很简单,只需要在命令行输入一下命令:
./gradlew findbugs
./gradlew pmd
./gradlew checkstyle
当命令已经成功执行,报告就会生成,你会在checkstyle和pmd中看到很多违规行为,但是这个可以帮助你提高代码质量,如果你不理解其中的违规行为只要点击该条连接就会解释是什么引起的。
也就是说,如果你愿意编写好的代码,你必须知道坏的代码是什么,糟糕的代码质量就像是异常等待发生的灾难。