OCLint的使用与集成
1,通过Homebrew安装
使用命令行
brew tap oclint/formulae
brew install oclint
2,下载安装包安装
1,进入OCLint在Github的地址,选择release,选择最新版本的安装包
2,解压下载文件。将文件存放到一个合适的位置。(比如我选择将这些需要的源代码存放到 Document 目录下)
3,在终端编辑当前环境的配置文件,将 bin 目录添加到 PATH 下,编辑 .bashrc 或
vim .bash_profile
OCLint_PATH=/Users/zjh48/Documents/oclint/build/oclint-release export PATH=$OCLint_PATH/bin:$PATH
或者
vim .zshrc
export PATH="/Users/gyenno/Documents/oclint-22.02/bin:$PATH"
4,将配置文件 source 一下。
source .bash_profile
或者
source .zshrc
5,验证是否安装成功。在终端输入
oclint --version
6,安装xcpretty,需要使用OCLint对日志信息进行分析运行命令,安装xcpretty,使用xcpretty命令分析日志信息。xcpretty是用来格式化xcodebuild输出的工具,使用ruby开发。安装:
gem install xcpretty
3,使用
cd到项目根目录,使用以下命令行
xcodebuild -scheme ZJHAnalyzeDemo -workspace ZJHAnalyzeDemo.xcworkspace clean && xcodebuild -scheme ZJHAnalyzeDemo -workspace ZJHAnalyzeDemo.xcworkspace -configuration Debug | xcpretty -r json-compilation-database -o compile_commands.json
oclint-json-compilation-database -e Pods -- -report-type html -o oclintReport.html
注明:某个文件夹进行分析
oclint-json-compilation-database -i 需要静态分析的文件夹或文件 -- -report-type html -o oclintReport.html 其他的参数
3,报错问题
1,报错:oclint: error: one compiler command contains multiple jobs
1,将 Project 和 Targets 中 Building Settings 下的 COMPILER_INDEX_STORE_ENABLE
设置为 NO
2,在 podfile 中 target ‘xx’ do 前面添加下面的脚本
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['COMPILER_INDEX_STORE_ENABLE'] = "NO"
end
end
end
2,报错:oclint: error: violations exceed threshold
看到报错信息是默认的警告数量超过限制,则 lint 失败。事实上 lint 后可以跟参数,所以我们修改脚本如下:
oclint-json-compilation-database -e Pods -- -report-type html -o oclintReport.html -rc LONG_LINE=9999 -max-priority-1=9999 -max-priority-2=9999 -max-priority-3=9999
4,OCLint的规则
1,可以通过 -e 参数忽略指定的文件,比如忽略Pods文件夹:
oclint-json-compilation-database -e Pods -- -o=report.html
2,通过-rc改变检查规则的默认值
比如有一条默认规则:long line [size|P3] Line with 137 characters exceeds limit of 100 ,这表示一个方法里的代码行数不能超过100,可以通过-rc改变默认100行的限制比如改成200行
oclint-json-compilation-database -- -rc=LONG_LINE=200 -o=report.html
3,通过 -disable-rule可以禁止某一规则,比如禁止LongLine长方法检查:
oclint-json-compilation-database -disable-rule=LongLine
4,命令的组合使用,组合的命令使用空格隔开,例如 -e Pods -rc=LONG_LINE=200
oclint-json-compilation-database -e Pods -rc=LONG_LINE=200-- -o=report.html
5,如果需要更改的规则比较多,可以通过.oclint 文件配置规则(暂未找到该文件在哪个地方)
6,忽略Pods以及第三方文件夹
oclint-json-compilation-database -e Pods -e GyennoMedical/ThirdLibrary -- -report-type html -o oclintReport.html -rc LONG_LINE=9999 -max-priority-1=9999 -max-priority-2=9999 -max-priority-3=9999
7,通过该脚本可以分模块进行检测,例如检测HomeModule
xcodebuild -scheme GyennoMedical -workspace GyennoMedical.xcworkspace clean && xcodebuild -scheme GyennoMedical -workspace GyennoMedical.xcworkspace -configuration Debug | xcpretty -r json-compilation-database -o compile_commands.json && oclint-json-compilation-database -i GyennoMedical/HomeModule -- -report-type html -o oclintReport.html
5,Xcode脚本使用
1、创建Aggregate项目
OClint 可以和 Xcode IDE 结合,把错误直接在 IDE 中显示出来。首先,我们在项目中创建一个新的 target,然后选择 Aggregate 作为模板。在项目的 TARGETS 下面,点击下方的 “+” ,选择 cross-platform 下面的 Aggregate。输入自定义名字,这里命名为 ZJHLint。注意我们可以建立多个 target,然后分别关注代码分析的多个方面。
2,添加 Run Script 脚本
选择对应的 TARGET -> ZJHLint。然后在 Build Phases 选项卡中选择 Add Run Script。
关于脚本的编写我们仍然选择最简单的方式,即 xcodebuild + xcpretty + oclint-json-compilation-database 的方式来做 oclint。脚本如下:
$ cd ${SRCROOT}
$ xcodebuild -scheme ZJHAnalyzeDemo -workspace ZJHAnalyzeDemo.xcworkspace clean && xcodebuild -scheme ZJHAnalyzeDemo -workspace ZJHAnalyzeDemo.xcworkspace -configuration Debug | xcpretty -r json-compilation-database -o compile_commands.json && oclint-json-compilation-database -e Pods -- -report-type Xcode
xcode中持续集成可使用脚本
export LC_CTYPE=en_US.UTF-8
cd ${SRCROOT}
xcodebuild -scheme GyennoMedical -workspace GyennoMedical.xcworkspace clean && xcodebuild -scheme GyennoMedical -workspace GyennoMedical.xcworkspace -configuration Debug | xcpretty -r json-compilation-database -o compile_commands.json && oclint-json-compilation-database -i GyennoMedical/HomeModule -- -report-type xcode
如oclint路径设置使用的是.zshrc,则使用以下命令集成到xcode中
source ~/.zshrc
cd ${PROJECT_DIR}
xcodebuild -scheme VideoTest -workspace VideoTest.xcworkspace clean
xcodebuild -scheme VideoTest -workspace VideoTest.xcworkspace -configuration Debug | xcpretty -r json-compilation-database -o compile_commands.json
oclint-json-compilation-database -e Pods -- -report-type xcode
3,运行Aggregate项目
然后我们就可以开始执行分析了,因为这里我们选择的 report-type 是 xcode,这时 oclint 发现的错误会直接在 IDE 中标示出来,方便我们对代码进行改进。当然这只是一种参考,不一定要采纳 oclint 给的提示。(我这边在Xcode运行脚本时,识别不出 xcpretty 指令,搜索了好久,还是没找到原因,这里先用了别人的截图)
6,OCLint自定义规则
1,首先在文件夹oclint-scripts,,使用./make执行脚本;(该过程可能需要翻墙才能完成)
2,在文件夹oclint-scripts执行./scaffoldRule GTETestRule -t ASTVisitor,创建自定义规则的文件;
3,在oclint的根目录创建文件夹oclint-xcoderules,执行完该命令后,会在oclint-rules/rules自动生成文件夹custom,其内有文件GTETestRule.cpp以及CMakeLists.txt;
4,cd到文件夹oclint-xcoderules,创建create-xcode-rules.sh;
5,脚本文件中输入内容如下:
#! /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
6,使用./create-xcode-rules.sh执行脚本;
7,执行完上述脚本后,会在oclint-xcoderules文件夹生成一个OCLINT_RULES工程,如下图:
8,打开工程可以看到所有的rule文件,所有规则都在里面,自定义的规则一般在最底部;
9,在工程顶部选择我们修改过的scheme,使用command+b编译;
10,编译完成后在Products文件可以看到我们要的dylib文件;
11,选中该文件右键,Show in Finder,可以看到dylib文件,将该文件复制到文件夹oclint/build/oclint-release/lib/oclint/rules则可以使用该规则了。
7,安装过程问题记录
1,执行完脚本sh create-xcode-rules.sh
以后,在工程哪个地方可以查看创建的rule
2,如何更新dylib
8,默认规则整理
规则文件 | 作用 | 备注 | 修改后的限制(需讨论) | 优先级 |
---|---|---|---|---|
LongMethodRule | 单个方法的行数限制,默认为50行 | |||
LongLineRule | 单行的字数限制,默认100字符 | |||
OCLintAbstractRule | 未知 | 未测试出来 | ||
BitwiseOperatorInConditionalRule | 条件判断语句中含有位操作符会提示 | 举例if (a & b) | ||
BrokenNullCheckRule | 无效检查的规则 | 未测试出来 | ||
BrokenOddnessCheckRule | 违反奇偶校验规则 | 未测试出来 | ||
CollapsibleIfStatementsRule | 可折叠的if语句规则,if语句可以折叠却未折叠使用时触发 | 举例if (str > 1) { if (str < 10) { }} | ||
ConstantConditionalOperatorRule | 条件运算符一直为真或者一直为假时触发 | |||
ConstantIfExpressionRule | 作用类似同上,具体未知 | |||
DeadCodeRule | 有永远无法被执行的代码时会触发 | 比如return后面的无效代码 | ||
DoubleNegativeRule | 有使用双重否定的代码时触发 | 未测试出来 | ||
ForLoopShouldBeWhileLoopRule | 有可以简化的for循环时触发,即可修改为while循环的代码 | 未测试出来 | ||
GotoStatementRule | 未知 | 未测试出来 | ||
JumbledIncrementerRule | 多重循环嵌套时递增错误时触发 | 例如;for (int i = 0; i < a; i++) {for (int j = 0; j < a; i++) { // references both ‘i’ and ‘j’ }} | ||
MisplacedNullCheckRule | 向空指针发送消息时会触发 | 未测试出来 | ||
MultipleUnaryOperatorRule | 多个一元运算符会触发 | 例如int b = -(+(!(~1))) | ||
ReturnFromFinallyBlockRule | 抛出异常时在finally使用return触发 | |||
ThrowExceptionFromFinallyBlockRule | 在finally抛出异常时会触发 | 未测试出来 | ||
ObjCVerifyIsEqualHashRule | 重写isEqual方法但没重写hash方法时会触发 | |||
ObjCVerifyMustCallSuperRule | 使用__attribute__((annotate(“oclint:enforce[base method]”)))修饰方法时,子类调用该方法但未实现super的时候会触发 | |||
ObjCVerifySubclassMustImplementRule | 未知 | 未测试出来 | ||
ObjCVerifyProhibitedCallRule | 使用__attribute__((annotate(“oclint:enforce[prohibited method]”)))修饰方法时,任何地方调用该方法都会触发 | |||
ObjCVerifyProtectedMethodRule | 使用__attribute__((annotate(“oclint:enforce[protected method]”)))修饰方法时,除了其本身和其子类的其他地方调用该方法都会触发,代表该方法只能其内部调用 | |||
AvoidBranchingStatementAsLastInLoopRule | for循环最后一句使用break会触发 | |||
BaseClassDestructorShouldBeVirtualOrProtectedRule | 未知 | 未测试出来 | ||
DefaultLabelNotLastInSwitchStatementRule | 在switch语句中,如果default不是写在最后则会触发 | |||
DestructorOfVirtualClassRule | 未知 | 未测试出来 | ||
InvertedLogicRule | 使用一些难以理解的逆向判断会触发 | |||
MissingBreakInSwitchStatementRule | switch语句中缺少break会触发 | |||
NonCaseLabelInSwitchStatementRule | 未知 | 未测试出来 | ||
ObjCAssignIvarOutsideAccessorsRule | 未知 | 未测试出来 | ||
ParameterReassignmentRule | 在方法中将方法的参数重新赋值时会触发 | |||
PreferEarlyExitRule | 方法中可以使用判断提前return却没有使用时会触发 | |||
SwitchStatementsShouldHaveDefaultRule | switch语句没有default时会提示 | 这种情况系统也有警告 | ||
CoveredSwitchStatementsDontNeedDefaultRule | 当switch语句涵盖了所有情况时不需要default,否则会触发 | |||
TooFewBranchesInSwitchStatementRule | 当判断较少时,使用switch而不使用if会触发 | |||
CudaBranchDivergenceRule | 未知 | 未测试出来 | ||
AvoidDefaultArgumentsOnVirtualMethodsRule | 未知 | 未测试出来 | ||
AvoidPrivateStaticMembersRule | 未知 | 未测试出来 | ||
EmptyCatchStatementRule | 未知 | 未测试出来 | ||
EmptyDoWhileStatementRule | do/while语句中未实现内容时会触发 | |||
EmptyElseBlockRule | if语句中的else未实现内容时会触发 | |||
EmptyFinallyStatementRule | cry/catch/finally语句中,finally中没有任何东西时会触发 | |||
EmptyForStatementRule | for循环语句中没有任何有用的代码时会触发 | |||
EmptyIfStatementRule | if语句中没有任何有用的代码时会触发 | |||
EmptySwitchStatementRule | switch语句中没有任何有用的代码时会触发 | |||
EmptyTryStatementRule | try语句中没有任何有用的代码时会触发 | |||
EmptyWhileStatementRule | while语句中没有任何有用的代码时会触发 | |||
ObjCBoxedExpressionsRule | 未知 | 未测试出来 | ||
ObjCContainerLiteralsRule | 不可变数组字典等集合类,创建时建议直接赋值,无需使用arrayWithObjects等方法,否则会触发 | |||
ObjCNSNumberLiteralsRule | 创建NSNumber类型常量时建议直接使用@(),无需使用numberWithInt等方法,否则会触发 | |||
ObjCObjectSubscriptingRule | 获取数组、字典等类型中的数据时,建议使用[],无需使用objectForKey和objectAtIndex,否则会触发 | |||
LongVariableNameRule | 变量名过长时会提示,默认20字符 | |||
ShortVariableNameRule | 变量名过短时会提示,默认3字符 | |||
RedundantConditionalOperatorRule | 赋值表达式使用多余的判断时会触发 | bool b1 = a > b ? true : false;应当使用bool b1 = a > b; | ||
RedundantIfStatementRule | if判断语句使用多余的判断时会触发 | |||
RedundantLocalVariableRule | 当一个变量刚声明就被return时,应该直接return声明该变量表达式右侧的值,否则会触发 | |||
RedundantNilCheckRule | 多余的nil判断会被触发 | |||
UnnecessaryElseStatementRule | if语句中被return的话,则无需写else语句,否则会触发 | |||
UnnecessaryNullCheckForCXXDeallocRule | 未知 | 未测试出来 | ||
UselessParenthesesRule | 检测一些无用的括号 | 例如return (0),应直接使用return 0 | ||
CyclomaticComplexityRule | 检测方法中的if、for、switch等语句是否超过10,超过则会触发 | |||
LongClassRule | 检测一个类中代码行数是否超过1000行,超过则会触发 | |||
LongLineRule | 检测一行代码行数是否超过100字符,超过则会触发 | |||
LongMethodRule | 检测一个方法中代码行数是否超过50行,超过则会触发 | |||
NcssMethodCountRule | 检测一个方法中有效行数是否超过30行(不算空行、括号等) | |||
NestedBlockDepthRule | 检测方法中的{}嵌套层数,默认5层 | |||
NPathComplexityRule | 未知 | 未测试出来 | ||
TooManyFieldsRule | 未知 | 未测试出来 | ||
TooManyMethodsRule | 方法过多时会触发 | |||
TooManyParametersRule | 方法参数过多时会触发,默认10个参数 | |||
UnusedLocalVariableRule | 定义了未使用的变量会触发 | |||
UnusedMethodParameterRule | 定义了未使用的方法参数会触发 |