OCLint+Xcode实现CodeReview

Code Review是开发过程中保证代码质量不可或缺的一部分,但是呢,要么是懒,要么是真没时间,在我们公司code review已从原来的流于形式到彻底废弃了。最近看了看项目代码,咋写的都有,看着确实难受,于是就动了“code review自动化”的念头。xcode里有内置的Analyser,但由于默认的规则太少导致功能实在很有限。找了半天,就盯上OCLint了。OCLint是啥我就不多说啦,具体可以查看OCLint官网。本篇博客记录了我如何使用oclint进行静态代码分析,只针对Mac。

10年积累的成都网站设计、网站制作经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站制作后付款的网站建设流程,更有斗门免费网站建设让你可以放心的选择与我们合作。

一、环境配置

需要安装oclintxcpretty

1、安装oclint

方法一:brew安装

命令行执行:

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

(1)进入到github上,下载最新(当前为oclint-0.13-x86_64-darwin-16.7.0.tar.gz)安装包,解压出来为oclint-0.13,放到如下目录:/Users/layne/OCLint,即路径为/Users/layne/OCLint/oclint-0.13
(2)将oclint添加到环境变量。vim打开~/.bash_profile(若没有则创建),添加如下代码:

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

终端执行:

 $oclint

出现如下内容证明没问题:

 oclint: Not enough positional command line arguments specified!
 Must specify at least 1 positional argument: See: oclint -help
方法三:源码安装 (若要自定义规则,则必须使用源码方式安装,后边会说到具体方法。)

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、打开终端进入到/Users/layne/OCLint/oclint-0.13/oclint-scripts

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

然后执行:

./make

之后就开始下载和编译,不过时间会比较长(40min左右),且还必须能够爬出去才可以。成功之后会有如下路径:/Users/layne/OCLint/oclint-0.13/build/oclint-release,这个就是oclint的路径。
4、添加oclint到环境变量。执行:

vim ~/.bash_profile

将如下内容写入:

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

保存退出。重启终端之后在终端执行:oclint --version,出现如下内容:

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

说明:这里安装的xcpretty是最新版,github上的oclint源码应该是针对最新版的xcpretty进行了兼容。为什么这么说呢?因为我一开始是采用的方法二安装的oclint,运行oclint现成的规则没有问题。之后想要自定义规则,但是方法三又太麻烦了,于是我就偷懒从网上下载了别人事先编译好的oclint-0.12(这里说的"编译好的oclint"保留了当初编译的“现场”,可以进行自定义规则,而方法二中的是“干净“的oclint),然后进行自定义规则,可是跑起来一直报错(形如"/usr/sh fail with exit code 1")。于是乎我不得不用oclint源码重新编译一遍,再运行的时候就没有错误了。

二、xcode配置

以项目LayneStudy为例。

1、创建Aggregate类型target

打开LayneStudy项目,new一个新的target,类型选择Aggregate,命名为OCLint,确定。说明:在xcode9中,Aggregate类型在Cross-platform等目录下(而非iOS、watchOS、macOS等目录下)。

2、编写shell脚本

(1)选择target OCLint,在build phases里添加New Run Script Phase。在框里输入如下脚本代码:

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

(2)编写脚本oclint.sh,内容如下:

 source ~/.bash_profile
 #获取项目路径
 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放到项目根目录下的oclint文件夹中(要先创建oclint文件夹)。最终目录结构如下:

 ../LayneStudy.xcodeproj
 ../LayneSutdy
 ../oclint
 ../oclint/oclint.sh
3、执行

回到xcode,scheme选择OCLint,command+B,编译完成之后xcode则出现各种警告,证明你成功了。

补充:

①若出现python错误,则通过设置环境变量使alias python=python3,即使用最新的python。
②若出现/Library/Ruby/Gems/2.3.0/gems/xcpretty-0.3.0/lib/xcpretty/parser.rb:434:in `===': invalid byte sequence in US-ASCII (ArgumentError) ”这种错误,则是编码问题:在~/.bash_profile中设置编码:

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

自定义规则

1、自定义阈值

像脚本oclint.sh中写的,使用-rc设置各种阈值,详见threshold command line,也可以通过写配置文件的形式配置阈值,参照threshold configuration file。有一点需要注意,配置文件要放到oclint-json-compilation-database命令执行的目录下,例如oclint.sh中有一段:

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

oclint-json-compilation-database是在$compilecommandsJsonFolderPath 中执行的,那么配置文件也要放到$compilecommandsJsonFolderPath下,且命名为.oclint(会被隐藏)。如果配置文件无法命名为.oclint,则需要vim创建一个名为.oclint的文件,并将配置的内容写入,最后移动它到$compilecommandsJsonFolderPath目录下。

2、自定义规则

通过自定义规则类,才是真正的自定义

默认规则

在下载的oclint包已经有默认的一些规则,路径如下:
/Users/layne/OCLint/oclint-0.13/lib/oclint/rules。你没看错,规则都是些以dylib结尾的动态库文件。若在oclint-json-compilation-database执行时没有指定规则加载的路径,那么将会加载这些默认的规则。若要自定义规则路径,则要改写oclint.sh 如下:

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

改为

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

(要事先在$compilecommandsJsonFolderPath目录下创建oclint_rules文件夹)这样oclint就会加载$compilecommandsJsonFolderPath/oclint_rules中的规则。你可以将一些默认规则文件放到这个目录下,也可以将自定义的规则文件放到这个目录下,进行统一管理。

自定义规则

再次强调: 若要自定义规则,则必须要使用oclint源码
OCLint提供了scaffoldRule工具进行自定义规则。
1、创建规则cpp文件。在如下路径处Users/layne/OCLint/oclint-0.13打开终端窗口,输入如下命令(可用的选项为:SourceCodeReader、ASTVisitor和ASTMatcher):

oclint-scripts/scaffoldRule ObjCNoSynthesize -t SourceCodeReader

这样就在以下路径生成了对应的cpp文件和MakeFile:

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

2、 为了方便开发,生成xcodeproj文件,使用xcode开发规则。
(1)在oclint-0.13目录下创建文件夹oclint-xcoderules
(2)进入到oclint-xcoderules目录(Users/layne/OCLint/oclint-0.13/oclint-xcoderules),创建shell文件create-xcode-rules.sh,内容如下:

#! /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的访问权限:

 chmod 777 create-xcode-rules.sh

然后执行:

 ./create-xcode-rules.sh

最后如果出现如下内容证明xcodeproj生成成功了:

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

并且在oclint-xcoderules文件夹下生成了工程目录。如下图:
OCLint+Xcode实现Code Review

3、双击打开OCLINT_RULES.xcodeproj,左侧显示所有的规则源文件,
OCLint+Xcode实现Code Review
拉到最底下就可以看到自己创建的规则ObjCNoSynthesize了。在ObjCNoSynthesizeRule.cpp中编写规则逻辑,之后在Scheme中选择对应的scheme,然后Command+B进行build,成功之后会在目录/Users/layne/OCLint/oclint-0.13/oclint-xcoderules/rules.dl/DEBUG中找到libObjCNoSynthesizeRule.dylib.至此我们就完成了规则的自定义。

4、创建新规则,即往OCLINT_RULES.xcodeproj项目中添加新规则。
(1)使用命令行创建新规则:
回到如下路径Users/layne/OCLint/oclint-0.13打开终端窗口,输入如下命令:

oclint-scripts/scaffoldRule ObjCPointerStarShouldBeNearerToVariable -t ASTVisitor  

(2)在OCLINT_RULES项目的scheme中随便选一个target,然后Commnand+B,这样新创建规则就会被加入到项目中来。

5、删除规则。
(1)从左边选择要删除的规则的cpp文件->delete->move to trash;
(2)打开对应的CMakeLists.txt,删除掉对应的配置。
(3)Command+B.
DONE!

补充说明:

1、规则的制定主要基于三个类:AbstractASTVisitorRule、AbstractASTMatcherRule和AbstractSourceCodeReaderRule,它们的关系如下:
RuleBase
   |
   |-AbstractASTRuleBase
   |      |_ AbstractASTVisitorRule
   |             |_AbstractASTMatcherRule
   |
   |-AbstractSourceCodeReaderRule
AbstractSourceCodeReaderRule:

提供eachLine方法,每行的读取源码。对对于想要从每行的内容编写规则的rule,可以使用继承自AbstractSourceCodeReaderRule。

AbstractASTVisitorRule:(一般继承这个类)

继承自AbstractASTVisitorRule的rule,可以实现访问AST上特定类型的所有节点,可以检查特定类型的所有节点是递归实现的,在AbstractASTVisitorRule的apply方法中可以看到代码实现,开发者只需要通过重写bool Visit*方法来访问特定类型的节点,在该函数中实现检查操作,其返回值往往是返回true,返回值表示是否继续递归检查。

AbstractASTMatcherRule: (目前没用过)

继承自AbstractASTMatcherRule的rule,实现setUpMatcher方法,在setUpMatcher()方法中实现添加matcher,当检查发现匹配的结果时,会调用callback()方法,故重新callback方法来对匹配的结果进行处理操作。

以上就是使用oclint的详细教程,至于自定义的规则如何去写,个人建议还是先看看现有规则的源码,找找感觉,然后再比着写。
下面是3个参考链接,我获益良多,建议深入阅读,尤其是里面的例子...

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


分享名称:OCLint+Xcode实现CodeReview
转载来源:http://myzitong.com/article/iehdos.html