iOS代碼靜態(tài)分析平臺搭建(二)之OCLint規(guī)則

OCLint內(nèi)置了72條檢測規(guī)則,如果對這些規(guī)則不加以自定義的話很可能會出現(xiàn)上萬條不規(guī)范的內(nèi)容,代碼是為了實(shí)現(xiàn)功能,規(guī)范也一定要注意,但是不能本末倒置,我找了一個比較老的工程進(jìn)行了測試,輸出的報(bào)告如下:



這個工程的代碼量其實(shí)還算不上很大,已經(jīng)出現(xiàn)了這么多不符合規(guī)則的內(nèi)容,粗略整理了一下,大概有三十多條檢測規(guī)則是代碼中比較常用的。

OCLint常見規(guī)則

規(guī)則名稱 自定義規(guī)則所對應(yīng)KEY值 含義 備注
long variable name LongVariableName 過長的變量名稱
long line LongLine 一行代碼包含過多的字符
empty else block EmptyElseBlock else語句中是空的
unused method parameter UnusedMethodParameter 未使用的參數(shù)
prefer early exits and continue PreferEarlyExit 如果存在退出語句,讓滿足退出條件的選項(xiàng)盡早退出 代碼示例
empty catch statement EmptyCatchStatement try-catchy語句中catch代碼塊為空
too many methods TooManyMethods 一個類中包含了過多的方法
collapsible if statements CollapsibleIfStatements 如果可以盡量合并if語句 代碼示例
ivar assignment outside accessors or init AssignIvarOutsideAccessors 某些成員變量的初始化不在get,set,init方法中 代碼示例
redundant nil check RedundantNilCheck 非必要的nil檢查 代碼示例
high ncss method HighNcssMethod “非注釋的源語句”過多,其實(shí)說的就是一個方法不包含注釋,有效的代碼量過大 代碼示例
high npath complexity HighNpathComplexity 一個方法中可能執(zhí)行的路徑總和過多 代碼示例
long method LongMethod 一個方法過于龐大,做了太多事情
high cyclomatic complexity HighCyclomaticComplexity 代碼圈度過高,包含了很多if else while等語句 代碼示例
empty if statement EmptyIfStatement if語句內(nèi)容為空
useless parentheses UselessParentheses 無用的括號 代碼示例
redundant conditional operator RedundantConditionalOperator 冗余的條件判斷 代碼示例
redundant local variable RedundantLocalVariable 多余的變量創(chuàng)建 代碼示例
unnecessary else statement UnnecessaryElseStatement 不必要的else判斷 代碼示例
unused local variable UnusedLocalVariable 定義了一個變量但未使用 代碼示例
dead code DeadCode 顧名思義,死代碼,所寫的邏輯不影響最終的執(zhí)行結(jié)果或者代碼不會被執(zhí)行 代碼示例
inverted logic InvertedLogic 逆邏輯,代碼的邏輯很難被理解 代碼示例
constant if expression ConstantIfExpression if語句的判斷總是true或者false 代碼示例
too few branches in switch statement TooFewBranchesInSwitchStatement switch語句的分支太少 代碼示例
missing default in switch statements MissingDefaultStatement switch語句卻少default 代碼示例
bitwise operator in conditional BitwiseOperatorInConditional 條件語句中使用了位運(yùn)算,位運(yùn)算很高效,但有時難以理解 代碼示例
unnecessary default statement in covered switch statement UnnecessaryDefaultStatement 不必要的default,switch已經(jīng)羅列出所有的case分支 代碼示例
redundant if statement RedundantIfStatement 沒必要的條件判斷 代碼示例
long class LongClass 太大的類,超過了1000行代碼 代碼示例
deep nested block DeepNestedBlock 太深的嵌套 代碼示例
missing break in switch statement MissingBreakInSwitchStatement switch語句缺少break 代碼示例
constant conditional operator ConstantConditionalOperator 常量條件運(yùn)算符,結(jié)果總為true或者false 代碼示例
broken oddness check BrokenOddnessCheck 奇數(shù)檢查不正確,出現(xiàn)這個問題大概率是使用%運(yùn)算進(jìn)行判斷 代碼示例
use number literal UseNumberLiteral 推薦直接使用數(shù)字來進(jìn)行初始化,而不是調(diào)用類方法 代碼示例
short variable name ShortVariableName 過短的變量名稱 代碼示例
use container literal UseContainerLiteral 推薦使用容器語法初始化數(shù)組字典等 代碼示例
parameter reassignment ParameterReassignment 參數(shù)被重新定義了,這是不標(biāo)準(zhǔn)的寫法 代碼示例
use object subscripting UseObjectSubscripting 不推薦使用下標(biāo)在數(shù)組或者字典中取值 代碼示例

定義具體檢測規(guī)則

上面所列出來的規(guī)則是可以根據(jù)我們的項(xiàng)目需要進(jìn)行自定義的,比如設(shè)置每行代碼最多200個字符。

-rc=LONG_LINE=200

設(shè)置變量名稱最長40個字符

-rc=LONG_VARIABLE_NAME=40

忽略某些檢測規(guī)則

-disable-rule ShortVariableName 
-disable-rule UseContainerLiteral
-disable-rule ParameterReassignment 
-disable-rule UseObjectSubscripting 

完整的檢測語句如下:

oclint-json-compilation-database -e Pods -e Applications -- -extra-arg=-Wno-everything -report-type html -o oclintReport.html \-rc=LONG_LINE=200 \-rc=LONG_VARIABLE_NAME=40 \-disable-rule ShortVariableName \-disable-rule UseContainerLiteral \-disable-rule ParameterReassignment \-disable-rule UseObjectSubscripting 

生成報(bào)告

可以選擇輸出html格式的報(bào)告,直接使用瀏覽器就可以查看結(jié)果。


結(jié)果查看起來還是非常方便的,會定位到具體的類以及對應(yīng)的行,還會將具體的錯誤類別展示出來。有一個點(diǎn)要注意,在生成編譯文件的時候要加上一句GCC_PRECOMPILE_PREFIX_HEADER=YES,預(yù)先編譯prefix文件,不然最終展示出來的報(bào)告會出現(xiàn)很多編譯問題,完整編譯語句如下:

xcodebuild clean build -scheme <your_scheme> -workspace <your_workspace>.xcworkspace -configuration Debug GCC_PRECOMPILE_PREFIX_HEADER=YES COMPILER_INDEX_STORE_ENABLE=NO -sdk iphoneos16.2 | xcpretty -r json-compilation-database -o compile_commands.json

腳本文件

每次都使用命令行進(jìn)行代碼的掃描,其實(shí)是很費(fèi)勁的一件事情,可以直接使用腳本文件進(jìn)行檢測。

#!/bin/bash

COLOR_ERR="\033[1;31m"    #出錯提示
COLOR_SUCC="\033[0;32m"  #成功提示
COLOR_QS="\033[1;37m"  #問題顏色
COLOR_AW="\033[0;37m"  #答案提示
COLOR_END="\033[1;34m"     #顏色結(jié)束符



# 尋找項(xiàng)目的 ProjectName
function searchProjectName () {
    # maxdepth 查找文件夾的深度
    find . -maxdepth 1 -name "*.xcodeproj"
}

function oclintForProject () {
    # 預(yù)先檢測所需的安裝包是否存在
    if which xcodebuild 2>/dev/null; then
    echo 'xcodebuild exist'
    else
    echo 'xcodebuild 未安裝,請安裝Xcode'
    fi
    
    if which oclint 2>/dev/null; then
    echo 'oclint exist'
    else
    export PATH="/Users/imac0823/Documents/Tools/oclint/bin:$PATH"
    source ~/.zshrc
    fi
    if which xcpretty 2>/dev/null; then
    echo 'xcpretty exist'
    else
    echo 'xcpretty 未安裝,請安裝xcpretty'
    fi
    
    
    # 指定編碼
    export LANG="zh_CN.UTF-8"
    export LC_COLLATE="zh_CN.UTF-8"
    export LC_CTYPE="zh_CN.UTF-8"
    export LC_MESSAGES="zh_CN.UTF-8"
    export LC_MONETARY="zh_CN.UTF-8"
    export LC_NUMERIC="zh_CN.UTF-8"
    export LC_TIME="zh_CN.UTF-8"
    export xcpretty=/usr/local/bin/xcpretty # xcpretty 的安裝位置可以在終端用 which xcpretty找到
    
    searchFunctionName=`searchProjectName`
    path=${searchFunctionName}
    # 字符串替換函數(shù)。//表示全局替換 /表示匹配到的第一個結(jié)果替換。
    path=${path//.\//}  # ./BridgeLabiPhone.xcodeproj -> BridgeLabiPhone.xcodeproj
    path=${path//.xcodeproj/} # BridgeLabiPhone.xcodeproj -> BridgeLabiPhone
    
    myworkspace=$path".xcworkspace" # workspace名字
    myscheme=$path  # scheme名字
    
    # 清除上次編譯數(shù)據(jù)
    DIR=~/Library/Developer/Xcode/DerivedData/
    echo -e $COLOR_SUCC'??????????清除上次編譯數(shù)據(jù)??????????'$COLOR_SUCC
    rm -r -- "$DIR"*

     # # 生成編譯數(shù)據(jù)
    xcodebuild GCC_PRECOMPILE_PREFIX_HEADER=YES COMPILER_INDEX_STORE_ENABLE=NO OTHER_CFLAGS="-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable" clean build -scheme $myscheme -workspace $myworkspace -configuration Debug -sdk iphoneos16.2 |tee xcodebuild.log|xcpretty -r json-compilation-database -o compile_commands.json

    if [ -f ./compile_commands.json ]; then
    echo -e $COLOR_SUCC'??????????xcpretty編譯數(shù)據(jù)生成完畢??????????'$COLOR_SUCC
    else
    echo -e $COLOR_ERR'???xcpretty編譯數(shù)據(jù)生成失敗???'$COLOR_ERR
    return -1
    fi

    if [ -f ./compile_commands.json ]; then
    echo -e $COLOR_SUCC'??????????xcpretty編譯數(shù)據(jù)生成完畢??????????'$COLOR_SUCC
    else
    echo -e $COLOR_ERR'???xcpretty編譯數(shù)據(jù)生成失敗???'$COLOR_ERR
    return -1
    fi

    echo -e $COLOR_SUCC'??????????OCLint代碼分析開始??????????'$COLOR_SUCC
    # 生成報(bào)表
    oclint-json-compilation-database -e Pods -e Applications -- -extra-arg=-Wno-everything -report-type html -o oclintReport.html \-rc=LONG_LINE=200 \-rc=LONG_VARIABLE_NAME=40 \-disable-rule ShortVariableName \-disable-rule UseContainerLiteral \-disable-rule ParameterReassignment \-disable-rule UseObjectSubscripting \-disable-rule AssignIvarOutsideAccessors \-disable-rule UnusedMethodParameter
    
    if [ -f ./oclintReport.html ]; then
    echo -e $COLOR_SUCC'??????????oclint分析數(shù)據(jù)生成完畢??????????'$COLOR_SUCC
    else
    echo -e $COLOR_ERR'???oclint分析數(shù)據(jù)生成失敗???'$COLOR_ERR
    return -1
    fi
  
}

oclintForProject $1


OCLint的不足之處

OCLint可以檢測出來許許多多代碼不規(guī)范的地方,這些不規(guī)范會影響代碼的可讀性問題,不易于維護(hù),時間長了會造成很多技術(shù)債,但是更深層次的問題比如資源泄漏,內(nèi)存泄漏這類問題OCLint是無法檢測出來的,需要借助其他工具,比如FacebookInfer,這個放到下一篇再去分享。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容