OCLint工具介紹
OCLint是一個(gè)靜態(tài)代碼掃描分析工具控淡,可用于提高代碼質(zhì)量和減少潛在的缺陷左敌,目前支持C逸雹,C++营搅,Objective-C,它可以?huà)呙璩龃a中存在的問(wèn)題梆砸,比如:
- 可能存在的錯(cuò)誤 - 比如空的 if/ else / try / catch / finally語(yǔ)句
- 未使用的代碼段 - 比如未使用的局部變量和參數(shù)等
- 過(guò)于復(fù)雜的代碼 - 比如多路徑判斷等
- 冗余的代碼 - 比如冗余的if語(yǔ)句和無(wú)用的括號(hào)等
- 不合理的代碼 - 比如超長(zhǎng)的方法和超長(zhǎng)的參數(shù)列表
- 錯(cuò)誤的做法 - 比如反轉(zhuǎn)邏輯转质,參數(shù)的重新分配
- …
該工具配合持續(xù)集成,自動(dòng)打包編譯帖世,可以很大程度的提高編碼的樂(lè)趣以及盡早的修復(fù)潛在的問(wèn)題以降低維護(hù)成本
安裝OCLint
OCLint是運(yùn)行于Linux和MacOX平臺(tái)上的開(kāi)源工具休蟹,可以直接下載源碼進(jìn)行編譯安裝,也可以使用作者發(fā)布的release版本進(jìn)行安裝
針對(duì)于MacOS系統(tǒng)日矫,可以直接通過(guò)Homebrew進(jìn)行安裝
1. 設(shè)置brew的第三方倉(cāng)庫(kù)
brew tap oclint/formulae
2. 安裝
brew install oclint
3. OCLint升級(jí)
brew update
brew upgrade oclint
使用OCLint
命令列表
oclint -help
1赂弓、生成格式化的編譯日志文件compile_commands.json
-
使用 xcodebuild 對(duì)工程進(jìn)行編譯
OCLint需要根據(jù)編譯日志里的文件信息對(duì)工程進(jìn)行掃描
xcodebuild -list 可以顯示項(xiàng)目相關(guān)的信息
以quidemo為例
通過(guò)以下命令對(duì)工程進(jìn)行編譯并將編譯的日志信息輸出到 xcodebuild.log 文件中
xcodebuild -target qmuidemo -configuration Debug -scheme qmuidemo| tee xcodebuild.log
- xcpretty 格式化編譯日志
直接使用OCLint對(duì)日志信息進(jìn)行分析
oclint-xcodebuild xcodebuild.log
得到輸出信息為:
This binary is no longer under maintenance by OCLint team.
Please consider using xcpretty (https://github.com/supermarin/xcpretty) instead!
提示需要使用xcpretty來(lái)分析日志信息,需要安裝xcpretty, xcpretty可對(duì)xcodebuild的輸出進(jìn)行格式化哪轿。并且可以輸出多種格式的日志信息盈魁,這里需要安裝xcpretty
gem install xcpretty
注:如果沒(méi)有權(quán)限,則在前面添加sudo窃诉,如果提示文件夾操作被禁止Operation not permitted - /usr/bin/rougify杨耙,則更改$GEM_HOME的路徑到/usr/local/bin使用sudo gem install xcpretty -n /usr/local/bin來(lái)安裝
xcpretty安裝之后,使用--report json-compilation-database或者-r json-compilation-database可以生成指定格式的數(shù)據(jù)飘痛,當(dāng)前指定為json格式珊膜。
運(yùn)行命令:
xcodebuild | xcpretty -r json-compilation-database -o compile_commands.json
如果沒(méi)有設(shè)置json輸出路徑,則默認(rèn)的路徑在build/reports中敦冬,需要移動(dòng)并改名為compile_commands.json到根目錄
如果你想獲取編譯日志辅搬,又想獲取格式化后的編譯日志可以這樣:
xcodebuild [flags] | tee xcodebuild.log | xcpretty -r json-compilation-database -o compile_commands.json
2、OCLint根據(jù)json格式化后的編譯日志信息對(duì)代碼進(jìn)行掃描分析
使用oclint-json-compilation-database命令對(duì)上一步生成的json數(shù)據(jù)進(jìn)行分析
將build/reports目錄中的compile_commands.json移動(dòng)到項(xiàng)目根目錄脖旱,然后運(yùn)行命令
oclint-json-compilation-database — -report-type=html -o=report.html
對(duì)項(xiàng)目代碼進(jìn)行分析堪遂,最終生成report.html文件
OCLint目前支持輸出html,json萌庆,xml溶褪,pmd,xcode格式文件
3践险、OCLint分析腳本
上面的步驟可以寫(xiě)成腳本:
#! /bin/sh
xcodebuild clean
xcodebuild | xcpretty -r json-compilation-database
cp build/reports/compilation_db.json compile_commands.json
oclint-json-compilation-database —-report-type=html -o=report.html
4猿妈、OCLint的規(guī)則
- 可以通過(guò) -e 參數(shù)忽略指定的文件吹菱,比如忽略Pods文件夾:
oclint-json-compilation-database -e Pods -- -o=report.html
- 通過(guò)-rc改變檢查規(guī)則的默認(rèn)值,比如有一條默認(rèn)規(guī)則:long line [size|P3] Line with 137 characters exceeds limit of 100 彭则,這表示一個(gè)方法里的代碼行數(shù)不能超過(guò)100鳍刷,可以通過(guò)-rc改變默認(rèn)100行的限制比如改成200行:
oclint-json-compilation-database -- -rc=LONG_LINE=200 -o=report.html
具體可以操作哪些規(guī)則,可以去官網(wǎng)查詢(xún)
- 通過(guò) -disable-rule可以禁止某一規(guī)則,比如禁止LongLine長(zhǎng)方法檢查:
oclint-json-compilation-database -disable-rule=LongLine
- 這些命令是可以組合使用俯抖,比如:
oclint-json-compilation-database -e Pods -rc=LONG_LINE=200-- -o=report.html
-
如果需要更改的規(guī)則比較多输瓜,可以通過(guò).oclint 文件配置規(guī)則
具體編寫(xiě)規(guī)則如下:
規(guī)則默認(rèn)值:
Name | Description | Default |
---|---|---|
CYCLOMATIC_COMPLEXITY | Cyclomatic complexity of a method | 10 |
LONG_CLASS | Number of lines for a C class or Objective-C interface, category, protocol, and implementation | 1000 |
LONG_LINE | Number of characters for one line of code | 100 |
LONG_METHOD | Number of lines for a method or function | 50 |
LONG_VARIABLE_NAME | Number of characters for a variable name | 20 |
MAXIMUM_IF_LENGTH | Number of lines for the if block that would prefer an early exists | 15 |
MINIMUM_CASES_IN_SWITCH | Count of case statements in a switch statement | 3 |
NPATH_COMPLEXITY | NPath complexity of a method | 200 |
NCSS_METHOD | Number of non-commenting source statements of a method | 30 |
NESTED_BLOCK_DEPTH | Depth of a block or compound statement | 5 |
SHORT_VARIABLE_NAME | Number of characters for a variable name | 3 |
TOO_MANY_FIELDS | Number of fields of a class | 20 |
TOO_MANY_METHODS | Number of methods of a class | 30 |
TOO_MANY_PARAMETERS | Number of parameters of a method | 10 |
例如:
disable-rules:
- LongLine
rulePaths:
- /etc/rules
rule-configurations:
- key: CYCLOMATIC_COMPLEXITY
value: 15
- key: NPATH_COMPLEXITY
value: 300
output: oclint.html
report-type: html
enable-clang-static-analyzer: false
在Xcode里使用OCLint
OCLint是支持在Xcode中直接顯示代碼分析結(jié)果的
-
給工程添加一個(gè)Aggregate的target
Aggregate
選中剛剛創(chuàng)建的Aggregate target,然后點(diǎn)Build Phases芬萍,然后點(diǎn)左上角的加號(hào)尤揣,添加一個(gè)Add Run Script
如果你使用的是xctool ,輸入這個(gè)腳本:
source~/.bash_profile
cd ${SRCROOT}
/path/to/xctool.sh -reporter json-compilation-database:compile_commands.json clean
/path/to/xctool.sh -reporter json-compilation-database:compile_commands.json build
oclint-json-compilation-database|sed's/\(.*\.\m\{1,2\}:[0-9]*:[0-9]*:\)/\1 warning:/'
如果你使用的是自帶的xcodebuild柬祠,使用這個(gè)腳本
source~/.bash_profile
cd ${SRCROOT}
xcodebuild clean
xcodebuild|xcpretty -r json-compilation-database
oclint-json-compilation-database -- -report-type xcode
- 選中該target北戏,點(diǎn)擊編譯
如果提示不存在.bash_profile文件,則手動(dòng)創(chuàng)建該文件漫蛔,由于該文件是隱藏文件嗜愈,所有得先執(zhí)行命令
defaults write com.apple.finder AppleShowAllFiles TRUE
讓Finder顯示隱藏文件,然后強(qiáng)制重新啟動(dòng)Finder惩猫,然后Command+Shift+G前往文件夾芝硬,填寫(xiě)~查看,若無(wú)此文件轧房,命令行進(jìn)入次目錄創(chuàng)建一個(gè)即可:
cd ~
touch .bash_profile
恢復(fù)隱藏文件的隱藏
defaults write com.apple.finder AppleShowAllFiles FALSE
后重新啟動(dòng)Finder
4拌阴、結(jié)果
結(jié)果
控制OCLint的檢查
有的時(shí)候,我們?cè)谝阎欢未a會(huì)產(chǎn)生OCLint的警告奶镶,但是因?yàn)槟承┰虺僭撸覀儧](méi)法去修改該段代碼,或者沒(méi)有更好的修改方法厂镇,這時(shí)候纤壁,我們可以在代碼中控制OCLint忽略對(duì)這段代碼的檢查
1. 注解
可以使用注解的方法禁止OCLint的檢查,語(yǔ)法是:
__attribute__((annotate("oclint:suppress[unused method parameter]")))
比如我們知道一個(gè)參數(shù)沒(méi)有使用捺信,而又不想產(chǎn)生警告信息就可以這樣寫(xiě)酌媒,下面這段代碼可以忽略對(duì)sender的警告但是沒(méi)法忽略對(duì)參數(shù)i的警告:
- (IBAction)turnoverValueChanged: (id) __attribute__((annotate("oclint:suppress[unused method parameter]"))) sender
{
int i;// 這個(gè)參數(shù)不會(huì)被忽略,會(huì)產(chǎn)生OCLint警告
[self calculateTurnover];
}
對(duì)于方法的注解可以這樣寫(xiě)迄靠,下面方法中產(chǎn)生的警告都會(huì)被忽略掉:
bool __attribute__((annotate("oclint:suppress"))) aMethod(int aParameter)
{
// 這個(gè)方法里所有的警告都會(huì)被忽略
// 比如下面這個(gè)空的if警告會(huì)被忽略
if (1) {}
return true;
}
2.!OCLint
也可以通過(guò)//!OCLint
注釋的方式秒咨,不讓OCLint檢查。比如掌挚,禁止對(duì)未使用的參數(shù)unusedLocalVariable進(jìn)行檢查:
void a() {
int unusedLocalVariable; //!OCLINT
}
注釋要寫(xiě)在對(duì)應(yīng)的行上面才能禁止對(duì)應(yīng)的檢查雨席,比如對(duì)于空的if/else
禁止檢查的注釋為:
if (true) //!OCLint
{
// it is empty
}