概述: 簡要描述 OCLint 的安裝以及使用,最后給出一個(gè)自動(dòng)評(píng)審的 shell 腳本;
參考資料:
OCLint
xcpretty
轉(zhuǎn)載請(qǐng)表明: 文章出處:http://www.reibang.com/p/aa4305aa5468
完整腳本下載:https://github.com/hehtao/OCLint
一.OCLint 是什么?
官方原話如下:
OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code and looking for potential problems like:
Possible bugs - empty if/else/try/catch/finally statements
Unused code - unused local variables and parameters
Complicated code - high cyclomatic complexity, NPath complexity and high NCSS
Redundant code - redundant if statement and useless parentheses
Code smells - long method and long parameter list
Bad practices - inverted logic and parameter reassignment
...
Static code analysis is a critical technique to detect defects that aren't visible to compilers. OCLint automates this inspection process with advanced features:
Relying on the abstract syntax tree of the source code for better accuracy and efficiency; False positives are mostly reduced to avoid useful results sinking in them.
Dynamically loading rules into system, even in the runtime.
Flexible and extensible configurations ensure users in customizing the behaviors of the tool.
Command line invocation facilitates continuous integration and continuous inspection of the code while being developed, so that technical debts can be fixed early on to reduce the maintenance cost.
簡單描述就是:
OCLint是一個(gè)靜態(tài)代碼分析工具,提高質(zhì)量和減少缺陷通過檢查C 模孩、C++ 和Objective-C 代碼和尋找潛在的問題,如:
- 可能的缺陷 - 空的if / else / try / catch / finally語句
- 未使用的代碼 - 未使用的局部變量和參數(shù)
- 復(fù)雜的代碼 - 很高的圈復(fù)雜度,NPath復(fù)雜性和太高的NCSS
- 代碼異味 - 長方法和參數(shù)列表
- 長方法和參數(shù)列表不好的實(shí)踐——倒邏輯和參數(shù)重新分配
…....
二.OCLint 安裝:
1. 安裝OCLint:
brew tap oclint/formulae
brew install oclint
2. 安裝xcpretty:
gem install xcpretty
3. 更新:
brew update
brew upgrade oclint
三.使用:
先來看一串終端命令(稍后一句一句解釋):
cd yourProjectPath //你的工程所在目錄
xcodebuild clean // 相當(dāng)于 bulid clean
xcodebuild | xcpretty -r json-compilation-database // 生成json 格式的編譯文件,保存在工程目錄下的 build/reports文件,文件名稱為compilation_db.json
cp build/reports/compilation_db.json compile_commands.json // 將compilation_db.json 文件拷貝至當(dāng)前目錄并rename為compile_commands.json
oclint-json-compilation-database -e Pods -- -rc=LONG_LINE=200 -rc=NCSS_METHOD=100 -o=report.html //忽略 Pods 文件,-rc 執(zhí)行規(guī)則每行最大字節(jié)長度為200字符, 忽略注釋后括號(hào)后的有效代碼行數(shù)40行;
oclint-json-compilation-database 相關(guān)規(guī)則:
# --命名
# 變量名字最長字節(jié)
#-rc=LONG_VARIABLE_NAME=20 /
# 變量名字最短字節(jié)
#-disable-rule ShortVariableName /
# --size
# 圈復(fù)雜度
#-re=CYCLOMATIC_COMPLEXITY=10 /
# 每個(gè)類最行數(shù)
#-rc=LONG_CLASS=700 /
# 每行字節(jié)數(shù)量
#-rc=LONG_LINE=200 /
# 每個(gè)方法行數(shù)
#-rc=LONG_METHOD=80 /
# 忽略注釋后括號(hào)后的有效代碼行數(shù)
#-rc=NCSS_METHOD=40 /
# 嵌套深度
#-rc=NESTED_BLOCK_DEPTH=5 /
# 字段數(shù)量
#-rc=TOO_MANY_FIELDS=20 /
# 方法數(shù)量
#-rc=TOO_MANY_METHODS=30 /
# 方法參數(shù)
#-rc=TOO_MANY_PARAMETERS=6
正常情況下,執(zhí)行完上述命令此時(shí)在你的工程目錄里已經(jīng)生成了一個(gè) report.html,長得下面這個(gè)樣子:
是不是懵逼了? 這是什么鬼東西? 怎么可以這么丑?確定不是亂碼么?很負(fù)責(zé)的說這就是分析的結(jié)果呀!!! 接下來我們把它變好看些:
修改上面最后一條指令如下:
oclint-json-compilation-database -e Pods -- -report-type html -rc=LONG_LINE=200 -rc=NCSS_METHOD=100 -o=report.html //-report-type html 表示分析后輸出的文件類型為HTML截亦,查看其他支持的文件類型
再來看一下新生成的 report.html 文件:
是不是清爽了很多? 也許你又說了,可是我還是看不懂啊!!!!!莫慌,且看我來解釋:
OCLint的分析結(jié)果:
優(yōu)先級(jí)的級(jí)別是從Priority 1, Priority 2, Priority 3 依次降低的
Total Files 總文件數(shù)
Files with Violations 違規(guī)文件數(shù)
Compiler Warnings 表示項(xiàng)目中的警告??
Compiler Errors 表示編譯錯(cuò)誤
Location 表示警告的位置
Rule Name 規(guī)則名稱
Localtion 問題所在位置
一起讀一條:
描述信息如下:
- Priority: 3;
- Files:文件位置 xxxxx/Controller/DTAllWebController.m
- Localtion: 代碼不符規(guī)則的位置: 29:33 第29行第33個(gè)字符開始的位置;
- Rule Name: unused method parameter;
- Message: 這些自己看吧;
到此,基本的使用已經(jīng)講完了,規(guī)則可以也已根據(jù)需求自定義;
但是,注意這個(gè)但是來了,每次寫終端寫一堆東西,好麻煩呀,咱們來寫個(gè)腳本吧;
GOGOGO....
四.OCLint 腳本:
那么問題來了,腳本怎么寫?沒寫過啊,我也不知道啊!!!!Google吧;
來一個(gè)簡單地 shell "hello world" 腳本各位欣賞一下:
echo 'hello world'
是不是簡單至極??意不意外,驚不驚喜 .....
大概描述一下shell 編輯過程:
- 打開終端輸入 vim 點(diǎn)擊 "i" 進(jìn)入 insert模式,注意左下角;
- 輸入 echo 'hello world',按 esc 進(jìn)入命令行模式;
- 輸入 :wq test.sh 文件保存為 test.sh 并退出 vim 模式;
- chmod +x test.sh 命令,更改test.sh 權(quán)限;
- ./test.sh 執(zhí)行,輸出 hello world;
下面來寫OCLint 的腳本,仿造上面的流程:
將 echo 'hello world' 替換為:
xcodebuild clean
xcodebuild | xcpretty -r json-compilation-database
cp build/reports/compilation_db.json compile_commands.json
oclint-json-compilation-database -e Pods -- -report-type html -rc=LONG_LINE=200 -rc=NCSS_METHOD=100 -o=report.html
最終保存為: 你喜歡的名字.sh 例如:oclint.sh
腳本使用:
cd 至工程所在目錄.執(zhí)行 ./oclint.sh ,終端開始刷屏 .......
五. xcodebuild 命令報(bào)錯(cuò)解決方案:
如果你風(fēng)騷的裝了多個(gè)xcode(我是789全都有 ...) ,執(zhí)行xcodebuild可能會(huì)遇到如下錯(cuò)誤:
CoreSimulator detected Xcode.app relocation or
CoreSimulatorService version change. Framework path
(/Library/Developer/PrivateFrameworks/CoreSimulator.framework
) and version (494.4) does not match existing job path
(/Applications/Xcode.app/Contents/Developer/Library/PrivateFra
meworks/CoreSimulator.framework/Versions/A/XPCServices/com
.apple.CoreSimulator.CoreSimulatorService.xpc) and version
(375.21). Attempting to remove the stale service in order to add
the expected version.
解決方案如下:
終端執(zhí)行如下命令:
launchctl remove com.apple.CoreSimulator.CoreSimulatorService || true
六. 完整的shell腳本:
if which oclint 2>/dev/null; then
echo 'oclint exist'
else
brew tap oclint/formulae
brew install oclint
fi
if which xcpretty 2>/dev/null; then
echo 'xcpretty exist'
else
gem install xcpretty
fi
xcodebuild clean
xcodebuild -workspace=grid -scheme=grid | xcpretty -r json-compilation-database
cp build/reports/compilation_db.json compile_commands.json
oclint-json-compilation-database -e Pods -- \
-report-type html \
-rc=LONG_VARIABLE_NAME=20 \
-rc=ShortVariableName=4 \
-rc=LONG_CLASS=700 \
-rc=LONG_METHOD=80 \
-rc=LONG_LINE=200 \
-rc=NCSS_METHOD=120 \
-rc=NESTED_BLOCK_DEPTH=5 \
-rc=TOO_MANY_FIELDS=20 \
-rc=TOO_MANY_METHODS=30 \
-rc=TOO_MANY_PARAMETERS=6 \
-o=report.html
open ./report.html
簡單解釋一下上面的 if which oclint 2>/dev/null
shell 的 if 語句一般格式:
if ....; then
....
elif ....; then
....
else
....
fi
which 命令: 判斷某個(gè)指令是否純?cè)?純?cè)趧t默認(rèn)將結(jié)果打印在控制臺(tái);
" >/dev/null "將之前的結(jié)果重定向到/dev/null,不在控制臺(tái)打印;