本文對(duì)比iOS常用的幾種靜態(tài)分析工具虾攻,分析優(yōu)缺點(diǎn),并從中選出適合當(dāng)前工程的工具延刘,本文的應(yīng)用系統(tǒng)為macOS镣隶。
clang
xcode目前已經(jīng)集成了clang了极谊,可以直接用Xcode-》Product-》Analyze對(duì)代碼進(jìn)行靜態(tài)分析。也可以用如下命令行實(shí)現(xiàn)
cd Test
xcodebuild analyze -project Test.xcodeproj -scheme Test -sdk iphonesimulator -configuration Debug CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang"
clang會(huì)分析對(duì)應(yīng)工程的代碼安岂,并將結(jié)果輸出到clang文件夾下轻猖。
--html 生成分析結(jié)果的html文件。
- clang的優(yōu)點(diǎn):
跟xcode的集成度比較高域那,也支持命令行咙边,使用方便,解析速度較快。 - 缺點(diǎn):
檢查規(guī)則較少败许,這個(gè)在下文會(huì)有詳細(xì)介紹友瘤。
oclint
oclint也是iOS常用的代碼靜態(tài)分析工具,基于clang檐束。目前包含70個(gè)規(guī)則文件,基本涵蓋了clang的檢驗(yàn)規(guī)則束倍,并在此基礎(chǔ)上添加了較多代碼規(guī)范性規(guī)則被丧。可以在這里:http://docs.oclint.org/en/stable/rules/index.html查看具體規(guī)則绪妹。
- 安裝
brew tap oclint/formulae
brew install oclint
或者直接到官網(wǎng)https://github.com/oclint/oclint/releases/tag/v20.11下載最新release版本解壓即可甥桂。
#設(shè)置環(huán)境變量
cd oclint-20.11
export PATH=$pwd/oclint/bin:$PATH
source ~/.bash_profile
- 分析代碼
cd Test
xcodebuild -project Test.xcodeproj -scheme Test -configuration Debug -sdk iphonesimulator clean
xcodebuild -project Test.xcodeproj -scheme Test -configuration Debug -sdk iphonesimulator | xcpretty -r json-compilation-database -o compile_commands.json
oclint-json-compilation-database -- -report-type html -o oclintReport.html
主要流程是通過(guò)xcodebuild編譯工程,之后用xcpretty輸出標(biāo)準(zhǔn)格式的json文件邮旷,最后oclint-json-compilation-database分析json文件黄选,并以html格式輸出結(jié)果。
- oclint的優(yōu)點(diǎn):
輸出結(jié)果的文件整潔好看婶肩,支持自定義規(guī)則办陷。 - 缺點(diǎn):
解析較慢,規(guī)則太多太雜律歼,很多都是代碼硬性規(guī)范民镜。
infer
infer是Facebook開(kāi)源的代碼靜態(tài)分析工具,同樣是基于clang险毁,可以分析c制圈、objC和java代碼。
- 安裝
brew install infer
或者通過(guò)源碼安裝畔况,可以從https://github.com/facebook/infer/blob/master/INSTALL.md了解源碼安裝的詳細(xì)步驟鲸鹦。
首先更新依賴(lài)庫(kù)
brew install autoconf automake cmake opam pkg-config sqlite gmp mpfr
brew cask install adoptopenjdk8
之后下載infer并build,這個(gè)過(guò)程可能需要1個(gè)多小時(shí)
# Checkout Infer
git clone https://github.com/facebook/infer.git
cd infer
# Compile Infer
./build-infer.sh clang
# install Infer system-wide...
sudo make install
# ...or, alternatively, install Infer into your PATH
export PATH=`pwd`/infer/bin:$PATH
- 分析代碼
infer分析代碼需要區(qū)分兩種情況跷跪,第一種沒(méi)有使用pods馋嗜、carthage等代碼依賴(lài)管理工具的工程,可以直接跑下面的命令進(jìn)行分析
cd Test
infer run -- xcodebuild -target Test -configuration Debug -sdk iphonesimulator
對(duì)于使用了pods域庇、carthage等代碼依賴(lài)管理工具的工程嵌戈,直接跑infer run命令會(huì)報(bào)錯(cuò),需要先利用xcodebuild和xcpretty去生成標(biāo)準(zhǔn)格式的json文件听皿,再用infer去分析它并輸出結(jié)果熟呛。
cd Test
xcodebuild -project Test.xcodeproj -scheme Test -configuration Debug -sdk iphonesimulator clean
xcodebuild -project Test.xcodeproj -scheme Test -configuration Debug -sdk iphonesimulator | xcpretty -r json-compilation-database -o compile_commands.json
infer run --keep-going --compilation-database-escaped compile_commands.json
infer explore --html
- 分析過(guò)程中可能遇到的問(wèn)題
-
clang-9: error: unknown argument: '-index-store-path'
這是因?yàn)閤code多了一個(gè)-index-store-path構(gòu)建命令,而infer跟oclint都不支持這個(gè)構(gòu)建命令尉姨,我們可以通過(guò)修改工程build setting中Enable index-While-Building Functionality設(shè)置為NO來(lái)避免這個(gè)問(wèn)題庵朝。
當(dāng)然如果不想對(duì)工程配置做出修改,那么只需要在xcodebuild的時(shí)候設(shè)置對(duì)應(yīng)參數(shù)即可。
xcodebuild -showBuildSettings查找'-index-store-path'對(duì)應(yīng)key值為COMPILER_INDEX_STORE_ENABLE九府,xcodebuild的時(shí)候椎瘟,將其置于NO,這樣對(duì)工程就不會(huì)有任何影響了侄旬。
xcodebuild -project Test.xcodeproj -scheme Test -configuration Debug -sdk iphonesimulator COMPILER_INDEX_STORE_ENABLE=NO
-
infer生成中間文件肺蔚,開(kāi)始掃描時(shí)報(bào)錯(cuò)
需要注意的是,infer在一些環(huán)境下解析到最后一步會(huì)報(bào)錯(cuò)儡羔,并且輸出如下圖宣羊。這個(gè)問(wèn)題在infer的github上也有多人上報(bào),但目前并未解決汰蜘。但是慶幸的是仇冯,此時(shí)iner分析所需要的中間代碼文件已經(jīng)生成,所以只要在跑一次infer命令族操,即可生成最終結(jié)果苛坚。
- infer的優(yōu)點(diǎn):
規(guī)則相對(duì)較完善,容易暴露開(kāi)發(fā)工程中可能引起問(wèn)題的代碼色难。 - 缺點(diǎn):
解析速度慢泼舱,且與oclint一樣有大量代碼硬性規(guī)范造成的誤報(bào)。
驗(yàn)證Demo
為了更直觀地對(duì)比幾種工具的分析結(jié)果莱预,筆者做了一個(gè)小demo列舉了一些開(kāi)發(fā)中常出現(xiàn)的不規(guī)范代碼柠掂,并分別用3種方式分析對(duì)比其結(jié)果。
通過(guò)clang掃描可以?huà)叱?未使用變量依沮、字典或者數(shù)組插入空值涯贞、參數(shù)類(lèi)型不匹配等幾種情況。
通過(guò)oclint掃描可以?huà)叱?未使用變量危喉、參數(shù)類(lèi)型不匹配以及一些命名規(guī)范類(lèi)的提示宋渔。
通過(guò)infer掃描可以?huà)叱?可選方法不安全調(diào)用、strong聲明為weak辜限、傳參類(lèi)型不匹配皇拣、未驗(yàn)空、字典或者數(shù)組插入空值等幾種情況薄嫡。
對(duì)比可以看出氧急,infer在檢驗(yàn)規(guī)則較多、定位也較為準(zhǔn)確毫深。所以目前筆者采用的是infer作為靜態(tài)分析工具吩坝。
小記:
靜態(tài)分析工具只是輔助,目前開(kāi)發(fā)中大量的代碼問(wèn)題沒(méi)法通過(guò)靜態(tài)分析定位哑蔫。諸如監(jiān)聽(tīng)未移除钉寝、timer未停止弧呐、野指針、應(yīng)用場(chǎng)景中導(dǎo)致的循環(huán)引用等都無(wú)法準(zhǔn)確定位嵌纲。所以開(kāi)發(fā)中還是需要養(yǎng)成良好的開(kāi)發(fā)習(xí)慣和代碼規(guī)范俘枫。