靜態(tài)代碼分析工具廣泛用于Java開(kāi)發(fā)未舟,以改進(jìn)代碼庫(kù)并識(shí)別潛在的漏洞和設(shè)計(jì)缺陷。每個(gè)工具都有自己的特點(diǎn)典格,目的和優(yōu)勢(shì)俊扭,這有助于提高代碼質(zhì)量妨退。
FindBugs
- 主要用于分析Java字節(jié)碼赠涮,用于查找設(shè)計(jì)缺陷和潛在錯(cuò)誤华弓。
- 需要編譯代碼才能解決問(wèn)題芭挽,由于工作在字節(jié)碼級(jí)別滑废,所以速度會(huì)很快蝗肪。
- 此工具的主要類(lèi)別包括:正確性,錯(cuò)誤操作策严,多線程正確性穗慕,性能問(wèn)題饿敲,代碼漏洞妻导,安全性。
PMD
- 他分析JavaCC生成的抽象語(yǔ)法樹(shù)怀各,不需要實(shí)際編譯
- 它識(shí)別潛在的問(wèn)題倔韭,主要是無(wú)用代碼和重復(fù)代碼,循環(huán)的復(fù)雜性瓢对,過(guò)度復(fù)雜的表達(dá)式以及CheckStyle幾乎所有的功能寿酌。
Checkstyle
- 主要用來(lái)分析源代碼,并著眼通過(guò)遍歷Checkstyle生成的簡(jiǎn)單AST來(lái)改進(jìn)編碼標(biāo)準(zhǔn)
- 它驗(yàn)證源代碼的編碼約定硕蛹,如標(biāo)題醇疼,導(dǎo)入,空格法焰,格式等秧荆。
現(xiàn)在我們開(kāi)始在項(xiàng)目中集成,對(duì)于每個(gè)工具都需要編寫(xiě)相對(duì)應(yīng)的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要執(zhí)行的任務(wù)乙濒,這里是findbugs
excludeFilter: 自定義的規(guī)則
classes: 要進(jìn)行分析的字節(jié)碼
html.destination: 你需要定義生成的報(bào)告所存儲(chǔ)的位置
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"
}
}
請(qǐng)注意這里xml.enabled設(shè)置的是true,如前所述卵蛉,checkstyle對(duì)自己生成的AST起作用颁股,因此需要?jiǎng)?chuàng)建樹(shù)檢查器,即xml.enabled設(shè)置為false時(shí)傻丝,會(huì)出現(xiàn)下錯(cuò)誤:
無(wú)法創(chuàng)建檢查器:
/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腳本和規(guī)則都要放到你的項(xiàng)目的根目錄下的/tools文件夾下甘有,所有的規(guī)則和腳本都在 Github上可以找到。你可能需要配置規(guī)則并根據(jù)你實(shí)際需要以及可以避免的情況編寫(xiě)排除內(nèi)容葡缰,需要完成的最后一件事就是在應(yīng)用程序gradle文件中定義腳本梧疲。
apply from: "$project.rootDir/tools/findbugs.gradle"
apply from: "$project.rootDir/tools/checkstyle.gradle"
apply from: "$project.rootDir/tools/pmd.gradle"
現(xiàn)在所有的地方都已經(jīng)設(shè)置正確了,已經(jīng)為每個(gè)SCA工具編寫(xiě)了自己的規(guī)則和gradle腳本运准,現(xiàn)在要生成報(bào)告很簡(jiǎn)單幌氮,只需要在命令行輸入一下命令:
./gradlew findbugs
./gradlew pmd
./gradlew checkstyle
當(dāng)命令已經(jīng)成功執(zhí)行,報(bào)告就會(huì)生成胁澳,你會(huì)在checkstyle和pmd中看到很多違規(guī)行為该互,但是這個(gè)可以幫助你提高代碼質(zhì)量,如果你不理解其中的違規(guī)行為只要點(diǎn)擊該條連接就會(huì)解釋是什么引起的韭畸。
也就是說(shuō)宇智,如果你愿意編寫(xiě)好的代碼蔓搞,你必須知道壞的代碼是什么,糟糕的代碼質(zhì)量就像是異常等待發(fā)生的災(zāi)難随橘。