溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

OCLint+Xcode實(shí)現(xiàn)Code Review

發(fā)布時(shí)間:2020-04-29 13:15:42 來(lái)源:網(wǎng)絡(luò) 閱讀:10232 作者:zlayne 欄目:移動(dòng)開(kāi)發(fā)

Code Review是開(kāi)發(fā)過(guò)程中保證代碼質(zhì)量不可或缺的一部分,但是呢,要么是懶,要么是真沒(méi)時(shí)間,在我們公司code review已從原來(lái)的流于形式到徹底廢棄了。最近看了看項(xiàng)目代碼,咋寫(xiě)的都有,看著確實(shí)難受,于是就動(dòng)了“code review自動(dòng)化”的念頭。xcode里有內(nèi)置的Analyser,但由于默認(rèn)的規(guī)則太少導(dǎo)致功能實(shí)在很有限。找了半天,就盯上OCLint了。OCLint是啥我就不多說(shuō)啦,具體可以查看OCLint官網(wǎng)。本篇博客記錄了我如何使用oclint進(jìn)行靜態(tài)代碼分析,只針對(duì)Mac。

一、環(huán)境配置

需要安裝oclintxcpretty。

1、安裝oclint

方法一:brew安裝

命令行執(zhí)行:

$brew tap oclint/formulae   
$brew install oclint
方法二:安裝包安裝

(1)進(jìn)入到github上,下載最新(當(dāng)前為oclint-0.13-x86_64-darwin-16.7.0.tar.gz)安裝包,解壓出來(lái)為oclint-0.13,放到如下目錄:/Users/layne/OCLint,即路徑為/Users/layne/OCLint/oclint-0.13
(2)將oclint添加到環(huán)境變量。vim打開(kāi)~/.bash_profile(若沒(méi)有則創(chuàng)建),添加如下代碼:

 OCLINT_HOME=/Users/layne/OCLint/oclint-0.13
 export PATH=$OCLINT_HOME/bin:$PATH

終端執(zhí)行:

 $oclint

出現(xiàn)如下內(nèi)容證明沒(méi)問(wèn)題:

 oclint: Not enough positional command line arguments specified!
 Must specify at least 1 positional argument: See: oclint -help
方法三:源碼安裝 (若要自定義規(guī)則,則必須使用源碼方式安裝,后邊會(huì)說(shuō)到具體方法。)

1、安裝CMake和Ninja

brew install cmake ninja

CMake和Ninja是代碼編譯工具,因此必須要先安裝。
2、從github上下載oclint源碼,解壓之后重命名為oclint-0.13,然后放到如下目錄(隨意):/Users/layne/OCLint,最終為/Users/layne/OCLint/oclint-0.13
3、打開(kāi)終端進(jìn)入到/Users/layne/OCLint/oclint-0.13/oclint-scripts

cd /Users/layne/OCLint/oclint-0.13/oclint-scripts

然后執(zhí)行:

./make

之后就開(kāi)始下載和編譯,不過(guò)時(shí)間會(huì)比較長(zhǎng)(40min左右),且還必須能夠爬出去才可以。成功之后會(huì)有如下路徑:/Users/layne/OCLint/oclint-0.13/build/oclint-release,這個(gè)就是oclint的路徑。
4、添加oclint到環(huán)境變量。執(zhí)行:

vim ~/.bash_profile

將如下內(nèi)容寫(xiě)入:

OCLINT_HOME=/Users/layne/OCLint/oclint-0.13/build/oclint-release
export PATH=$OCLINT_HOME/bin:$PATH

保存退出。重啟終端之后在終端執(zhí)行:oclint --version,出現(xiàn)如下內(nèi)容:

LLVM (http://llvm.org/):
LLVM version 5.0.0svn-r.320669
Optimized build.
Default target: x86_64-apple-darwin17.3.0
Host CPU: broadwell

OCLint (http://oclint.org/):
OCLint version 0.13.
Built Dec 14 2017 (16:03:48).

至此oclint安裝成功。

2、安裝xcpretty

 gem install xcpretty

說(shuō)明:這里安裝的xcpretty是最新版,github上的oclint源碼應(yīng)該是針對(duì)最新版的xcpretty進(jìn)行了兼容。為什么這么說(shuō)呢?因?yàn)槲乙婚_(kāi)始是采用的方法二安裝的oclint,運(yùn)行oclint現(xiàn)成的規(guī)則沒(méi)有問(wèn)題。之后想要自定義規(guī)則,但是方法三又太麻煩了,于是我就偷懶從網(wǎng)上下載了別人事先編譯好的oclint-0.12(這里說(shuō)的"編譯好的oclint"保留了當(dāng)初編譯的“現(xiàn)場(chǎng)”,可以進(jìn)行自定義規(guī)則,而方法二中的是“干凈“的oclint),然后進(jìn)行自定義規(guī)則,可是跑起來(lái)一直報(bào)錯(cuò)(形如"/usr/sh fail with exit code 1")。于是乎我不得不用oclint源碼重新編譯一遍,再運(yùn)行的時(shí)候就沒(méi)有錯(cuò)誤了。

二、xcode配置

以項(xiàng)目LayneStudy為例。

1、創(chuàng)建Aggregate類(lèi)型target

打開(kāi)LayneStudy項(xiàng)目,new一個(gè)新的target,類(lèi)型選擇Aggregate,命名為OCLint,確定。說(shuō)明:在xcode9中,Aggregate類(lèi)型在Cross-platform等目錄下(而非iOS、watchOS、macOS等目錄下)。

2、編寫(xiě)shell腳本

(1)選擇target OCLint,在build phases里添加New Run Script Phase。在框里輸入如下腳本代碼:

 chmod -R 777 $SRCROOT/oclint
 $SRCROOT/oclint/oclint.sh

(2)編寫(xiě)腳本oclint.sh,內(nèi)容如下:

 source ~/.bash_profile
 #獲取項(xiàng)目路徑
 PROJECT_DIR=$(cd `dirname $0`;cd ..;pwd)
 cd ${PROJECT_DIR}

 buildPath="${PROJECT_DIR}/oclint/build"
 compilecommandsJsonFolderPath="${PROJECT_DIR}/oclint"
 compilecommandsJsonFilePath="${PROJECT_DIR}/oclint/compile_commands.json"

 rm -rf "$compilecommandsJsonFolderPath/build"

 xcodebuild SYMROOT=$buildPath | xcpretty -r json-compilation-database -o $compilecommandsJsonFilePath

 cd $compilecommandsJsonFolderPath

 oclint-json-compilation-database -- -report-type xcode \
 -rc CYCLOMATIC_COMPLEXITY=10 \
 -rc LONG_CLASS=1000 \
 -rc LONG_METHOD=50 \
 -rc LONG_LINE=140 \
 -rc LONG_VARIABLE_NAME=30 \
 -rc SHORT_VARIABLE_NAME=1 \
 -rc MAXIMUM_IF_LENGTH=5 \
 -rc MINIMUM_CASES_IN_SWITCH=2 \
 -rc NCSS_METHOD=30 \
 -rc NESTED_BLOCK_DEPTH=5 \
 -rc TOO_MANY_METHOD=30 \
 -rc TOO_MANY_PARAMETERS=5 \
 -max-priority-1 0 \
 -max-priority-2 5 \
 -max-priority-3 10

將oclint.sh放到項(xiàng)目根目錄下的oclint文件夾中(要先創(chuàng)建oclint文件夾)。最終目錄結(jié)構(gòu)如下:

 ../LayneStudy.xcodeproj
 ../LayneSutdy
 ../oclint
 ../oclint/oclint.sh
3、執(zhí)行

回到xcode,scheme選擇OCLint,command+B,編譯完成之后xcode則出現(xiàn)各種警告,證明你成功了。

補(bǔ)充:

①若出現(xiàn)python錯(cuò)誤,則通過(guò)設(shè)置環(huán)境變量使alias python=python3,即使用最新的python。
②若出現(xiàn)/Library/Ruby/Gems/2.3.0/gems/xcpretty-0.3.0/lib/xcpretty/parser.rb:434:in `===': invalid byte sequence in US-ASCII (ArgumentError) ”這種錯(cuò)誤,則是編碼問(wèn)題:在~/.bash_profile中設(shè)置編碼:

export LANGUAGE=en_US.UTF-8
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

自定義規(guī)則

1、自定義閾值

像腳本oclint.sh中寫(xiě)的,使用-rc設(shè)置各種閾值,詳見(jiàn)threshold command line,也可以通過(guò)寫(xiě)配置文件的形式配置閾值,參照threshold configuration file。有一點(diǎn)需要注意,配置文件要放到oclint-json-compilation-database命令執(zhí)行的目錄下,例如oclint.sh中有一段:

 ......
 cd $compilecommandsJsonFolderPath
 oclint-json-compilation-database -- -report-type xcode \
 ......

oclint-json-compilation-database是在$compilecommandsJsonFolderPath 中執(zhí)行的,那么配置文件也要放到$compilecommandsJsonFolderPath下,且命名為.oclint(會(huì)被隱藏)。如果配置文件無(wú)法命名為.oclint,則需要vim創(chuàng)建一個(gè)名為.oclint的文件,并將配置的內(nèi)容寫(xiě)入,最后移動(dòng)它到$compilecommandsJsonFolderPath目錄下。

2、自定義規(guī)則

通過(guò)自定義規(guī)則類(lèi),才是真正的自定義 。

默認(rèn)規(guī)則

在下載的oclint包已經(jīng)有默認(rèn)的一些規(guī)則,路徑如下:
/Users/layne/OCLint/oclint-0.13/lib/oclint/rules。你沒(méi)看錯(cuò),規(guī)則都是些以dylib結(jié)尾的動(dòng)態(tài)庫(kù)文件。若在oclint-json-compilation-database執(zhí)行時(shí)沒(méi)有指定規(guī)則加載的路徑,那么將會(huì)加載這些默認(rèn)的規(guī)則。若要自定義規(guī)則路徑,則要改寫(xiě)oclint.sh 如下:

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

改為

 ......
 oclint-json-compilation-database -- -R $compilecommandsJsonFolderPath/oclint_rules -report-type xcode \
 ......

(要事先在$compilecommandsJsonFolderPath目錄下創(chuàng)建oclint_rules文件夾)這樣oclint就會(huì)加載$compilecommandsJsonFolderPath/oclint_rules中的規(guī)則。你可以將一些默認(rèn)規(guī)則文件放到這個(gè)目錄下,也可以將自定義的規(guī)則文件放到這個(gè)目錄下,進(jìn)行統(tǒng)一管理。

自定義規(guī)則

再次強(qiáng)調(diào): 若要自定義規(guī)則,則必須要使用oclint源碼
OCLint提供了scaffoldRule工具進(jìn)行自定義規(guī)則。
1、創(chuàng)建規(guī)則cpp文件。在如下路徑處Users/layne/OCLint/oclint-0.13打開(kāi)終端窗口,輸入如下命令(可用的選項(xiàng)為:SourceCodeReader、ASTVisitor和ASTMatcher):

oclint-scripts/scaffoldRule ObjCNoSynthesize -t SourceCodeReader

這樣就在以下路徑生成了對(duì)應(yīng)的cpp文件和MakeFile:

oclint-rules/rules/custom
oclint-rules/test/custom

2、 為了方便開(kāi)發(fā),生成xcodeproj文件,使用xcode開(kāi)發(fā)規(guī)則。
(1)在oclint-0.13目錄下創(chuàng)建文件夾oclint-xcoderules
(2)進(jìn)入到oclint-xcoderules目錄(Users/layne/OCLint/oclint-0.13/oclint-xcoderules),創(chuàng)建shell文件create-xcode-rules.sh,內(nèi)容如下:

#! /bin/sh -e

cmake -G Xcode \
      -D CMAKE_CXX_COMPILER=../build/llvm-install/bin/clang++  \
      -D CMAKE_C_COMPILER=../build/llvm-install/bin/clang \
      -D OCLINT_BUILD_DIR=../build/oclint-core \
      -D OCLINT_SOURCE_DIR=../oclint-core \
      -D OCLINT_METRICS_SOURCE_DIR=../oclint-metrics \
      -D OCLINT_METRICS_BUILD_DIR=../build/oclint-metrics \
      -D LLVM_ROOT=../build/llvm-install/ ../oclint-rules

保存退出之后,更改create-xcode-rules.sh的訪問(wèn)權(quán)限:

 chmod 777 create-xcode-rules.sh

然后執(zhí)行:

 ./create-xcode-rules.sh

最后如果出現(xiàn)如下內(nèi)容證明xcodeproj生成成功了:

 ......
 -- Configuration done
 -- Generating done
 -- Build files have been written to:/Users/layne/OCLint/oclint-0.13/oclint-xcoderules   

并且在oclint-xcoderules文件夾下生成了工程目錄。如下圖:
OCLint+Xcode實(shí)現(xiàn)Code Review

3、雙擊打開(kāi)OCLINT_RULES.xcodeproj,左側(cè)顯示所有的規(guī)則源文件,
OCLint+Xcode實(shí)現(xiàn)Code Review
拉到最底下就可以看到自己創(chuàng)建的規(guī)則ObjCNoSynthesize了。在ObjCNoSynthesizeRule.cpp中編寫(xiě)規(guī)則邏輯,之后在Scheme中選擇對(duì)應(yīng)的scheme,然后Command+B進(jìn)行build,成功之后會(huì)在目錄/Users/layne/OCLint/oclint-0.13/oclint-xcoderules/rules.dl/DEBUG中找到libObjCNoSynthesizeRule.dylib.至此我們就完成了規(guī)則的自定義。

4、創(chuàng)建新規(guī)則,即往OCLINT_RULES.xcodeproj項(xiàng)目中添加新規(guī)則。
(1)使用命令行創(chuàng)建新規(guī)則:
回到如下路徑Users/layne/OCLint/oclint-0.13打開(kāi)終端窗口,輸入如下命令:

oclint-scripts/scaffoldRule ObjCPointerStarShouldBeNearerToVariable -t ASTVisitor  

(2)在OCLINT_RULES項(xiàng)目的scheme中隨便選一個(gè)target,然后Commnand+B,這樣新創(chuàng)建規(guī)則就會(huì)被加入到項(xiàng)目中來(lái)。

5、刪除規(guī)則。
(1)從左邊選擇要?jiǎng)h除的規(guī)則的cpp文件->delete->move to trash;
(2)打開(kāi)對(duì)應(yīng)的CMakeLists.txt,刪除掉對(duì)應(yīng)的配置。
(3)Command+B.
DONE!

補(bǔ)充說(shuō)明:

1、規(guī)則的制定主要基于三個(gè)類(lèi):AbstractASTVisitorRule、AbstractASTMatcherRule和AbstractSourceCodeReaderRule,它們的關(guān)系如下:
RuleBase
   |
   |-AbstractASTRuleBase
   |      |_ AbstractASTVisitorRule
   |             |_AbstractASTMatcherRule
   |
   |-AbstractSourceCodeReaderRule
AbstractSourceCodeReaderRule:

提供eachLine方法,每行的讀取源碼。對(duì)對(duì)于想要從每行的內(nèi)容編寫(xiě)規(guī)則的rule,可以使用繼承自AbstractSourceCodeReaderRule。

AbstractASTVisitorRule:(一般繼承這個(gè)類(lèi))

繼承自AbstractASTVisitorRule的rule,可以實(shí)現(xiàn)訪問(wèn)AST上特定類(lèi)型的所有節(jié)點(diǎn),可以檢查特定類(lèi)型的所有節(jié)點(diǎn)是遞歸實(shí)現(xiàn)的,在AbstractASTVisitorRule的apply方法中可以看到代碼實(shí)現(xiàn),開(kāi)發(fā)者只需要通過(guò)重寫(xiě)bool Visit*方法來(lái)訪問(wèn)特定類(lèi)型的節(jié)點(diǎn),在該函數(shù)中實(shí)現(xiàn)檢查操作,其返回值往往是返回true,返回值表示是否繼續(xù)遞歸檢查。

AbstractASTMatcherRule: (目前沒(méi)用過(guò))

繼承自AbstractASTMatcherRule的rule,實(shí)現(xiàn)setUpMatcher方法,在setUpMatcher()方法中實(shí)現(xiàn)添加matcher,當(dāng)檢查發(fā)現(xiàn)匹配的結(jié)果時(shí),會(huì)調(diào)用callback()方法,故重新callback方法來(lái)對(duì)匹配的結(jié)果進(jìn)行處理操作。

以上就是使用oclint的詳細(xì)教程,至于自定義的規(guī)則如何去寫(xiě),個(gè)人建議還是先看看現(xiàn)有規(guī)則的源碼,找找感覺(jué),然后再比著寫(xiě)。
下面是3個(gè)參考鏈接,我獲益良多,建議深入閱讀,尤其是里面的例子...

http://oriochan.com/codeReview01.html
https://juejin.im/post/595370986fb9a06bcb7f7d56
http://blog.csdn.net/hdwhappy/article/details/61924772

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI