iOS工程自動化之靜態(tài)代碼分析OCLint

寫在前面

剛?cè)肼毜臅r候剥扣,博哥交代給我一個任務(wù)宜鸯,讓我調(diào)研一款叫SonarQube的靜態(tài)代碼分析工具坎怪,我當時跪在了CentOS與Java環(huán)境配置的混合雙打中岖沛。痛定思痛暑始,我還是先從專精C語言家族靜態(tài)代碼分析的工具OCLint入手開始做一些工作吧。

OCLint是什么

OCLint是一款靜態(tài)代碼分析工具,它可以用來檢查C婴削,C++廊镜,Objective-C的代碼、從而提高代碼的質(zhì)量馆蠕、減少潛在的問題期升。它可以掃描出代碼中存在的問題惊奇,比如:

可能存在的錯誤 - 比如空的 if/ else / try / catch / finally語句

未使用的代碼段 - 比如未使用的局部變量和參數(shù)等

過于復(fù)雜的代碼 - 比如多路徑判斷等

冗余的代碼 - 比如冗余的if語句和無用的括號等

不合理的代碼 - 比如超長的方法和超長的參數(shù)列表

錯誤的做法 - 比如反轉(zhuǎn)邏輯,參數(shù)的重新分配

為什么要使用OCLint

做為一個靜態(tài)代碼分析工具播赁,我們引入 OCLint 的目的主要是為了提高我們的代碼質(zhì)量颂郎。通常我們提高代碼質(zhì)量的方式是通過 CodeReview,但是這個過程耗費的人工和時間往往較大容为,所以我們想通過 OCLint 的一些規(guī)則乓序,讓機器幫我們完成一部分代碼質(zhì)量的檢測,從而提高我們的工作效率坎背。

安裝OCLint

OCLint是運行于Linux和MacOX平臺上的開源工具替劈,可以直接下載源碼進行編譯安裝,也可以使用作者發(fā)布的release版本進行安裝

針對于MacOS系統(tǒng)得滤,可以直接通過Homebrew進行安裝

brew tap oclint/formulae

brew install oclint

當然陨献,如果你所在網(wǎng)絡(luò)環(huán)境不太友好,使用HomeBrew下載龜速的時候懂更,有條件的同學(xué)可以嘗試下載Github上的release版本壓縮包眨业,然后將下載好的壓縮包放在

~/Library/Caches/Homebrew/

路徑下,直接執(zhí)行brew install oclint命令即可安裝沮协。

針對對OCLint升級的方法:

brew update

brew upgrade oclint

使用brew cleanup可以清理舊版本的安裝數(shù)據(jù)龄捡。

xcodebuild

xcodebuild是xcode的編譯命令。

可以查看xcodebuild的版本信息:

xcodebuild -version

Xcode 9.0

Build version 9M202q

也可以查看當前系統(tǒng)的sdk以及其版本:

xcodebuild -showsdks

iOS SDKs:

iOS 11.0 -sdk iphoneos11.0

iOS Simulator SDKs:

Simulator - iOS 11.0 -sdk iphonesimulator11.0

macOS SDKs:

macOS 10.13 -sdk macosx10.13

tvOS SDKs:

tvOS 11.0 -sdk appletvos11.0

tvOS Simulator SDKs:

Simulator - tvOS 11.0 -sdk appletvsimulator11.0

watchOS SDKs:

watchOS 4.0 -sdk watchos4.0

watchOS Simulator SDKs:

Simulator - watchOS 4.0 -sdk watchsimulator4.0

需要使用xcodebuild [flags]命令進行編譯并把相關(guān)的日志信息輸入到xcodebuild.log中慷暂,需要在.xcodeproj文件所在的目錄里面運行聘殖。

xcodebuild | tee xocdebuild.log

在這個地方我遇到了個坑,因為我們的項目是使用CocoaPods來管理第三方庫的行瑞,所以項目生成了.xcworkspace文件奸腺。這時我們想要編譯整個項目則需要編譯.xcworkspace并指定scheme。

所以WorkSpace版本的編譯命令就變成了

xcodebuild -workspace XinRen.xcworkspace -scheme XinRen -sdk iphoneos11.0 -configuration Release | tee xcodebuild.log | xcpretty -r json-compilation-database -o compile_commands.json

其中-workspace是用來聲明workspace文件的蘑辑,-scheme是用來指定workspace中的scheme的洋机,-sdk用來選擇sdk版本坠宴,-configuration用來聲明使用哪種配置編譯洋魂。還有-arch用來指定architecture,使用armV7喜鼓,armV7S等副砍。

細心的你一定注意到了有一個叫上面的命令中有一個叫xcpretty的參數(shù),嗯庄岖,沒錯豁翎,為了使用它我們還得安裝一個xcpretty

gem install xcpretty

接下來就是編譯中的漫長等待了,喝杯咖啡隅忿,稍等一會心剥,我們發(fā)現(xiàn)目錄里多了兩個文件和一個文件夾邦尊。分別是xcodebuild.log,compile_commands.json和一個叫build的文件夾优烧。其中對我們有用的是那個叫compile_commands.json的文件蝉揍。后面我們將使用OCLint工具來分析這個json文件。

OCLint命令行指令

OCLint 包含三個命令行指令:

oclint:基礎(chǔ)指令畦娄。通過這個指令可以指定加載驗證規(guī)則又沾、編譯代碼、分析代碼和生成報告熙卡。

oclint-json-compilation-database:高級指令杖刷。通過這個指令可以從compile_commands.json文件中讀取配置信息并執(zhí)行 oclint。

oclint-xcodebuild:通過這個指令可以從 Xcode 的xcodebuild.log文件導(dǎo)出編譯選項并保存成 JSON Compilation Database 格式驳癌。然后把保存到compile_commands.json文件中滑燃。

然后我們來看一下每個指令的選項和功能:

oclint規(guī)則加載選項

-R <目錄>:指定規(guī)則加載的目錄⊥窍剩可以是多個目錄不瓶,用空格隔開,默認情況下會搜索 $(oclint 可執(zhí)行文件目錄)/../lib/oclint/rules灾杰。

-disable-rule <規(guī)則名> 通過規(guī)則名使某些驗證規(guī)則失效蚊丐。

-rc <參數(shù)>=<值> 修改某些閾值。

下面是一個簡單的示例:

oclint -R /path/to/rules -disable-rule GotoStatement

表示從?/path/to/rules?加載規(guī)則艳吠,然后使?GotoStatement?這個驗證規(guī)則失效麦备。

然后來看一下閾值,下面是 OCLint 里面一些常見的閾值:

CYCLOMATIC_COMPLEXITY循環(huán)嵌套數(shù)限制10

LONG_CLASS類行數(shù)限制1000

LONG_LINE每行的字符限制100

LONG_METHOD方法行數(shù)限制50

LONG_VARIABLE_NAME參數(shù)名字符限制20

MAXIMUM_IF_LENGTHif 的行數(shù)限制15

MINIMUM_CASES_IN_SWITCHswitch case 的最小數(shù)目3

NPATH_COMPLEXITY通過該方法的非循環(huán)執(zhí)行路徑數(shù)量限制200

NCSS_METHOD連續(xù)未注釋行數(shù)限制30

NESTED_BLOCK_DEPTHblock 嵌套層數(shù)限制5

SHORT_VARIABLE_NAME變量名的最小字符數(shù)限制3

TOO_MANY_FIELDS類成員限制20

TOO_MANY_METHODS類方法數(shù)限制30

TOO_MANY_PARAMETERS參數(shù)個數(shù)限制10

名稱

描述

默認值

我們也可以把這些閾值配置到項目的?.oclint?文件下昭娩,比如:

rule-configurations:

- key: CYCLOMATIC_COMPLEXITY

value: 15

- key: LONG_LINE

value: 50

編譯選項

可以通過?--?的方式在指令的最后添加編譯選項凛篙。比如我們通過下面的?clang?指令編譯一個文件:

clang -x objective-c -arch armv7 -std=gnu99 -fobjc-arc -O0 -isysroot /Developer/SDKs/iPhoneOS6.0.sdk -g -I./Pods/Headers -c RPActivityIndicatorManager.m

在 OCLint 里面就可以這么寫:

oclint [oclint options] RPActivityIndicatorManager.m -- -x objective-c -arch armv7 -std=gnu99 -fobjc-arc -O0 -isysroot /Developer/SDKs/iPhoneOS6.0.sdk -g -I./Pods/Headers -c

編譯數(shù)據(jù)庫選項

-p <構(gòu)建目錄>:選擇一個包含?compile_commands.json?文件的目錄作為構(gòu)建目錄。如果沒有指定構(gòu)建目錄栏渺,oclint 指令會查找第一個輸入文件的所有父目錄來找到?compile_commands.json?文件呛梆。

生成報告選項

-o <目錄>:指定報告的輸出目標。

-report-type <類型名>:指定報告輸出的類型磕诊。默認是普通文本填物。

報告輸出的類型有如下幾種:

Plain Text Report(text)

HTML Report(html)

XML Report(xml)

JSON Reporter (json)

PMD Reporter (pmd):這種類型主要提供給 CI 系統(tǒng)使用,在 CI 系統(tǒng)的展示會更友好霎终。

Xcode Reporter (xcode):主要提供給 Xcode 內(nèi)查看滞磺。

同樣,我們也可以把這個配置加入到 .oclint 文件中:

report-type: html

output: oclint.html

退出狀態(tài)選項

-max-priority-1 <閾值>

-max-priority-2 <閾值>

-max-priority-3 <閾值>

首先我們來看一下 OCLint 會返回的 5 種退出 Code:

0 - SUCCESS:成功莱褒。

1 - RULE_NOT_FOUND:沒有找到驗證規(guī)則击困。

2 - REPORTER_NOT_FOUND:沒有指定報告輸出地址。

3 - ERROR_WHILE_PROCESSING:驗證過程中出錯广凸。

4 - ERROR_WHILE_REPORTING:生成報告時出錯阅茶。

5 - VIOLATIONS_EXCEED_THRESHOLD:違反規(guī)則的次數(shù)超出閾值蛛枚。

然后我們來看一下各個優(yōu)先級默認的閾值:優(yōu)先級 3 的閾值為 20;優(yōu)先級 2 的閾值為 10脸哀;優(yōu)先級 1 的閾值為 0坤候。如果超過了其中任意一個閾值,就表示你的代碼質(zhì)量是不達標的企蹭,然后 OCLint 會返回 VIOLATIONS_EXCEED_THRESHOLD白筹。

全局分析項

-enable-global-analysis

開啟這個選項可以得到更準確的分析結(jié)果,但是相對耗時比較長谅摄,一般不采用徒河。

Clang靜態(tài)分析選項

-enable-clang-static-analyzer

如果開啟這個選項,OCLint 會 hook Clang 的編譯過程送漠,然后收集編譯信息然后添加到報告中顽照。需要注意的是:這也會增加分析的時間。

Debug選項

-debug

開啟這個選項會給出更詳細的信息闽寡。但是這個選項只有在 OCLint 的 debug 標示開啟的時候才有效代兵。

oclint-json-compilation-database過濾選項

-i INCLUDES, -include INCLUDES, –include INCLUDES:

-e EXCLUDES, -exclude EXCLUDES, –exclude EXCLUDES:

這兩個選項是指在 compile_commands.json 文件中配置的基礎(chǔ)上添加一些文件/目錄來執(zhí)行 oclint,或者讓一些文件/目錄不執(zhí)行 oclint爷狈。

這兩個選項支持正則匹配植影,因為這個命令是用 Python 寫的,所以正則的格式以Python 正則表達式語法為準涎永。

比如思币,我們一般不對第三方庫執(zhí)行 oclint ,這個時候可以用下面的指令來把 Pods 目錄排除:

oclint-json-compilation-database -e Pods

oclint的選項

可以通過--的方式在指令的最后 oclint 選項羡微。比如:

oclint-json-compilation-database -e Pods -- -o=report.html

在最后添加了一個 oclint 的 -o 選項谷饿,表示將報告輸出到當前目錄的 report.html 文件中。

調(diào)試選項

-v:通過這個選項可以輸出最終執(zhí)行的 oclint 指令妈倔。

-debug:開啟這個選項會給出更詳細的信息博投。但是同樣這個選項只有在 OCLint 的 debug 標示開啟的時候才有效。

與其他工具配合

嗯盯蝴,其實它可以跟很多工具搭配使用毅哗,比如oclint 可以和 Xcode IDE 結(jié)合,把錯誤直接在 IDE 中顯示出來结洼。

首先黎做,我們在項目中創(chuàng)建一個新的 target叉跛,然后選擇Aggregate作為模板松忍。

然后給這個 target 命名,注意我們可以建立多個 target筷厘,然后分別關(guān)注代碼分析的多個方面鸣峭。

然后在 Build Phases 選項卡中選擇 Add Run Script宏所。

關(guān)于腳本的編寫我們?nèi)匀贿x擇最簡單的方式,即 xcodebuild + xcpretty + oclint-json-compilation-database 的方式來做 oclint摊溶。腳本如下:

source ~/.bash_profile

cd ${PROJECT_DIR}

xcodebuild clean

xcodebuild -workspace LPDLogger.xcworkspace -configuration Debug -scheme LPDLogger-Example build | xcpretty -r json-compilation-database -o compile_commands.json

oclint-json-compilation-database -- -report-type xcode

然后我們就可以開始執(zhí)行分析了爬骤,因為這里我們選擇的 report-type 是 xcode,這時 oclint 發(fā)現(xiàn)的錯誤會直接在 IDE 中標示出來莫换,方便我們對代碼進行改進霞玄。

OCLint還可以搭配Jenkins使用,限于時間拉岁。這部分我還沒有實踐坷剧。有空的話可以繼續(xù)探索。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喊暖,一起剝皮案震驚了整個濱河市惫企,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌陵叽,老刑警劉巖狞尔,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異巩掺,居然都是意外死亡偏序,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門胖替,熙熙樓的掌柜王于貴愁眉苦臉地迎上來禽车,“玉大人,你說我怎么就攤上這事刊殉⊙乘ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵记焊,是天一觀的道長逸月。 經(jīng)常有香客問我,道長遍膜,這世上最難降的妖魔是什么碗硬? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮瓢颅,結(jié)果婚禮上恩尾,老公的妹妹穿的比我還像新娘。我一直安慰自己挽懦,他們只是感情好翰意,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般冀偶。 火紅的嫁衣襯著肌膚如雪醒第。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天进鸠,我揣著相機與錄音稠曼,去河邊找鬼。 笑死客年,一個胖子當著我的面吹牛霞幅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播量瓜,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蝗岖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤奢入,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后铅鲤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡枫弟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年邢享,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淡诗。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡骇塘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出韩容,到底是詐尸還是另有隱情款违,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布群凶,位于F島的核電站插爹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏请梢。R本人自食惡果不足惜赠尾,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望毅弧。 院中可真熱鬧气嫁,春花似錦、人聲如沸够坐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至邓馒,卻和暖如春嘶朱,著一層夾襖步出監(jiān)牢的瞬間蛾坯,已是汗流浹背光酣。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脉课,地道東北人救军。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像倘零,于是被迫代替她去往敵國和親唱遭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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