Android靜態(tài)代碼分析工具

原文地址:https://medium.com/mindorks/static-code-analysis-for-android-using-findbugs-pmd-and-checkstyle-3a2861834c6a

image.png

靜態(tài)代碼分析工具廣泛用于Java開(kāi)發(fā)未舟,以改進(jìn)代碼庫(kù)并識(shí)別潛在的漏洞和設(shè)計(jì)缺陷。每個(gè)工具都有自己的特點(diǎn)典格,目的和優(yōu)勢(shì)俊扭,這有助于提高代碼質(zhì)量妨退。

FindBugs

  1. 主要用于分析Java字節(jié)碼赠涮,用于查找設(shè)計(jì)缺陷和潛在錯(cuò)誤华弓。
  2. 需要編譯代碼才能解決問(wèn)題芭挽,由于工作在字節(jié)碼級(jí)別滑废,所以速度會(huì)很快蝗肪。
  3. 此工具的主要類(lèi)別包括:正確性,錯(cuò)誤操作策严,多線程正確性穗慕,性能問(wèn)題饿敲,代碼漏洞妻导,安全性。

PMD

  1. 他分析JavaCC生成的抽象語(yǔ)法樹(shù)怀各,不需要實(shí)際編譯
  2. 它識(shí)別潛在的問(wèn)題倔韭,主要是無(wú)用代碼和重復(fù)代碼,循環(huán)的復(fù)雜性瓢对,過(guò)度復(fù)雜的表達(dá)式以及CheckStyle幾乎所有的功能寿酌。

Checkstyle

  1. 主要用來(lái)分析源代碼,并著眼通過(guò)遍歷Checkstyle生成的簡(jiǎn)單AST來(lái)改進(jìn)編碼標(biāo)準(zhǔn)
  2. 它驗(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)難随橘。

引用

  1. https://github.com/noveogroup/android-check
  2. http://continuousdev.com/2015/08/checkstyle-vs-pmd-vs-findbugs/
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末喂分,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子机蔗,更是在濱河造成了極大的恐慌蒲祈,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萝嘁,死亡現(xiàn)場(chǎng)離奇詭異梆掸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)牙言,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)酸钦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人咱枉,你說(shuō)我怎么就攤上這事卑硫。” “怎么了蚕断?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵欢伏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我基括,道長(zhǎng)颜懊,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任风皿,我火速辦了婚禮河爹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘桐款。我一直安慰自己咸这,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布魔眨。 她就那樣靜靜地躺著媳维,像睡著了一般。 火紅的嫁衣襯著肌膚如雪遏暴。 梳的紋絲不亂的頭發(fā)上侄刽,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音朋凉,去河邊找鬼州丹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的墓毒。 我是一名探鬼主播吓揪,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼所计!你這毒婦竟也來(lái)了柠辞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤主胧,失蹤者是張志新(化名)和其女友劉穎叭首,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體讥裤,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡放棒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年姻报,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了己英。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吴旋,死狀恐怖损肛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荣瑟,我是刑警寧澤治拿,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站笆焰,受9級(jí)特大地震影響劫谅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嚷掠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一捏检、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧不皆,春花似錦贯城、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至犬耻,卻和暖如春踩晶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背枕磁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工渡蜻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人透典。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓晴楔,卻偏偏與公主長(zhǎng)得像顿苇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子税弃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容