Android静态代码分析工具

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

image.png

静态代码分析工具广泛用于Java开发,以改进代码库并识别潜在的漏洞和设计缺陷。每个工具都有自己的特点,目的和优势,这有助于提高代码质量。

FindBugs

  1. 主要用于分析Java字节码,用于查找设计缺陷和潜在错误。
  2. 需要编译代码才能解决问题,由于工作在字节码级别,所以速度会很快。
  3. 此工具的主要类别包括:正确性,错误操作,多线程正确性,性能问题,代码漏洞,安全性。

PMD

  1. 他分析JavaCC生成的抽象语法树,不需要实际编译
  2. 它识别潜在的问题,主要是无用代码和重复代码,循环的复杂性,过度复杂的表达式以及CheckStyle几乎所有的功能。

Checkstyle

  1. 主要用来分析源代码,并着眼通过遍历Checkstyle生成的简单AST来改进编码标准
  2. 它验证源代码的编码约定,如标题,导入,空格,格式等。

现在我们开始在项目中集成,对于每个工具都需要编写相对应的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中看到很多违规行为,但是这个可以帮助你提高代码质量,如果你不理解其中的违规行为只要点击该条连接就会解释是什么引起的。
也就是说,如果你愿意编写好的代码,你必须知道坏的代码是什么,糟糕的代码质量就像是异常等待发生的灾难。

引用

  1. https://github.com/noveogroup/android-check
  2. http://continuousdev.com/2015/08/checkstyle-vs-pmd-vs-findbugs/
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容