iOS代码静态分析平台搭建(二)之OCLint规则

2023-10-09  本文已影响0人  MichealXXX

OCLint内置了72条检测规则,如果对这些规则不加以自定义的话很可能会出现上万条不规范的内容,代码是为了实现功能,规范也一定要注意,但是不能本末倒置,我找了一个比较老的工程进行了测试,输出的报告如下:



这个工程的代码量其实还算不上很大,已经出现了这么多不符合规则的内容,粗略整理了一下,大概有三十多条检测规则是代码中比较常用的。

OCLint常见规则

规则名称 自定义规则所对应KEY值 含义 备注
long variable name LongVariableName 过长的变量名称
long line LongLine 一行代码包含过多的字符
empty else block EmptyElseBlock else语句中是空的
unused method parameter UnusedMethodParameter 未使用的参数
prefer early exits and continue PreferEarlyExit 如果存在退出语句,让满足退出条件的选项尽早退出 代码示例
empty catch statement EmptyCatchStatement try-catchy语句中catch代码块为空
too many methods TooManyMethods 一个类中包含了过多的方法
collapsible if statements CollapsibleIfStatements 如果可以尽量合并if语句 代码示例
ivar assignment outside accessors or init AssignIvarOutsideAccessors 某些成员变量的初始化不在get,set,init方法中 代码示例
redundant nil check RedundantNilCheck 非必要的nil检查 代码示例
high ncss method HighNcssMethod “非注释的源语句”过多,其实说的就是一个方法不包含注释,有效的代码量过大 代码示例
high npath complexity HighNpathComplexity 一个方法中可能执行的路径总和过多 代码示例
long method LongMethod 一个方法过于庞大,做了太多事情
high cyclomatic complexity HighCyclomaticComplexity 代码圈度过高,包含了很多if else while等语句 代码示例
empty if statement EmptyIfStatement if语句内容为空
useless parentheses UselessParentheses 无用的括号 代码示例
redundant conditional operator RedundantConditionalOperator 冗余的条件判断 代码示例
redundant local variable RedundantLocalVariable 多余的变量创建 代码示例
unnecessary else statement UnnecessaryElseStatement 不必要的else判断 代码示例
unused local variable UnusedLocalVariable 定义了一个变量但未使用 代码示例
dead code DeadCode 顾名思义,死代码,所写的逻辑不影响最终的执行结果或者代码不会被执行 代码示例
inverted logic InvertedLogic 逆逻辑,代码的逻辑很难被理解 代码示例
constant if expression ConstantIfExpression if语句的判断总是true或者false 代码示例
too few branches in switch statement TooFewBranchesInSwitchStatement switch语句的分支太少 代码示例
missing default in switch statements MissingDefaultStatement switch语句却少default 代码示例
bitwise operator in conditional BitwiseOperatorInConditional 条件语句中使用了位运算,位运算很高效,但有时难以理解 代码示例
unnecessary default statement in covered switch statement UnnecessaryDefaultStatement 不必要的default,switch已经罗列出所有的case分支 代码示例
redundant if statement RedundantIfStatement 没必要的条件判断 代码示例
long class LongClass 太大的类,超过了1000行代码 代码示例
deep nested block DeepNestedBlock 太深的嵌套 代码示例
missing break in switch statement MissingBreakInSwitchStatement switch语句缺少break 代码示例
constant conditional operator ConstantConditionalOperator 常量条件运算符,结果总为true或者false 代码示例
broken oddness check BrokenOddnessCheck 奇数检查不正确,出现这个问题大概率是使用%运算进行判断 代码示例
use number literal UseNumberLiteral 推荐直接使用数字来进行初始化,而不是调用类方法 代码示例
short variable name ShortVariableName 过短的变量名称 代码示例
use container literal UseContainerLiteral 推荐使用容器语法初始化数组字典等 代码示例
parameter reassignment ParameterReassignment 参数被重新定义了,这是不标准的写法 代码示例
use object subscripting UseObjectSubscripting 不推荐使用下标在数组或者字典中取值 代码示例

定义具体检测规则

上面所列出来的规则是可以根据我们的项目需要进行自定义的,比如设置每行代码最多200个字符。

-rc=LONG_LINE=200

设置变量名称最长40个字符

-rc=LONG_VARIABLE_NAME=40

忽略某些检测规则

-disable-rule ShortVariableName 
-disable-rule UseContainerLiteral
-disable-rule ParameterReassignment 
-disable-rule UseObjectSubscripting 

完整的检测语句如下:

oclint-json-compilation-database -e Pods -e Applications -- -extra-arg=-Wno-everything -report-type html -o oclintReport.html \-rc=LONG_LINE=200 \-rc=LONG_VARIABLE_NAME=40 \-disable-rule ShortVariableName \-disable-rule UseContainerLiteral \-disable-rule ParameterReassignment \-disable-rule UseObjectSubscripting 

生成报告

可以选择输出html格式的报告,直接使用浏览器就可以查看结果。


结果查看起来还是非常方便的,会定位到具体的类以及对应的行,还会将具体的错误类别展示出来。有一个点要注意,在生成编译文件的时候要加上一句GCC_PRECOMPILE_PREFIX_HEADER=YES,预先编译prefix文件,不然最终展示出来的报告会出现很多编译问题,完整编译语句如下:
xcodebuild clean build -scheme <your_scheme> -workspace <your_workspace>.xcworkspace -configuration Debug GCC_PRECOMPILE_PREFIX_HEADER=YES COMPILER_INDEX_STORE_ENABLE=NO -sdk iphoneos16.2 | xcpretty -r json-compilation-database -o compile_commands.json

脚本文件

每次都使用命令行进行代码的扫描,其实是很费劲的一件事情,可以直接使用脚本文件进行检测。

#!/bin/bash

COLOR_ERR="\033[1;31m"    #出错提示
COLOR_SUCC="\033[0;32m"  #成功提示
COLOR_QS="\033[1;37m"  #问题颜色
COLOR_AW="\033[0;37m"  #答案提示
COLOR_END="\033[1;34m"     #颜色结束符



# 寻找项目的 ProjectName
function searchProjectName () {
    # maxdepth 查找文件夹的深度
    find . -maxdepth 1 -name "*.xcodeproj"
}

function oclintForProject () {
    # 预先检测所需的安装包是否存在
    if which xcodebuild 2>/dev/null; then
    echo 'xcodebuild exist'
    else
    echo 'xcodebuild 未安装,请安装Xcode'
    fi
    
    if which oclint 2>/dev/null; then
    echo 'oclint exist'
    else
    export PATH="/Users/imac0823/Documents/Tools/oclint/bin:$PATH"
    source ~/.zshrc
    fi
    if which xcpretty 2>/dev/null; then
    echo 'xcpretty exist'
    else
    echo 'xcpretty 未安装,请安装xcpretty'
    fi
    
    
    # 指定编码
    export LANG="zh_CN.UTF-8"
    export LC_COLLATE="zh_CN.UTF-8"
    export LC_CTYPE="zh_CN.UTF-8"
    export LC_MESSAGES="zh_CN.UTF-8"
    export LC_MONETARY="zh_CN.UTF-8"
    export LC_NUMERIC="zh_CN.UTF-8"
    export LC_TIME="zh_CN.UTF-8"
    export xcpretty=/usr/local/bin/xcpretty # xcpretty 的安装位置可以在终端用 which xcpretty找到
    
    searchFunctionName=`searchProjectName`
    path=${searchFunctionName}
    # 字符串替换函数。//表示全局替换 /表示匹配到的第一个结果替换。
    path=${path//.\//}  # ./BridgeLabiPhone.xcodeproj -> BridgeLabiPhone.xcodeproj
    path=${path//.xcodeproj/} # BridgeLabiPhone.xcodeproj -> BridgeLabiPhone
    
    myworkspace=$path".xcworkspace" # workspace名字
    myscheme=$path  # scheme名字
    
    # 清除上次编译数据
    DIR=~/Library/Developer/Xcode/DerivedData/
    echo -e $COLOR_SUCC'🚀🚀🚀🚀🚀清除上次编译数据🚀🚀🚀🚀🚀'$COLOR_SUCC
    rm -r -- "$DIR"*

     # # 生成编译数据
    xcodebuild GCC_PRECOMPILE_PREFIX_HEADER=YES COMPILER_INDEX_STORE_ENABLE=NO OTHER_CFLAGS="-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable" clean build -scheme $myscheme -workspace $myworkspace -configuration Debug -sdk iphoneos16.2 |tee xcodebuild.log|xcpretty -r json-compilation-database -o compile_commands.json

    if [ -f ./compile_commands.json ]; then
    echo -e $COLOR_SUCC'🚀🚀🚀🚀🚀xcpretty编译数据生成完毕🚀🚀🚀🚀🚀'$COLOR_SUCC
    else
    echo -e $COLOR_ERR'❌❌❌xcpretty编译数据生成失败❌❌❌'$COLOR_ERR
    return -1
    fi

    if [ -f ./compile_commands.json ]; then
    echo -e $COLOR_SUCC'🚀🚀🚀🚀🚀xcpretty编译数据生成完毕🚀🚀🚀🚀🚀'$COLOR_SUCC
    else
    echo -e $COLOR_ERR'❌❌❌xcpretty编译数据生成失败❌❌❌'$COLOR_ERR
    return -1
    fi

    echo -e $COLOR_SUCC'🚀🚀🚀🚀🚀OCLint代码分析开始🚀🚀🚀🚀🚀'$COLOR_SUCC
    # 生成报表
    oclint-json-compilation-database -e Pods -e Applications -- -extra-arg=-Wno-everything -report-type html -o oclintReport.html \-rc=LONG_LINE=200 \-rc=LONG_VARIABLE_NAME=40 \-disable-rule ShortVariableName \-disable-rule UseContainerLiteral \-disable-rule ParameterReassignment \-disable-rule UseObjectSubscripting \-disable-rule AssignIvarOutsideAccessors \-disable-rule UnusedMethodParameter
    
    if [ -f ./oclintReport.html ]; then
    echo -e $COLOR_SUCC'🚀🚀🚀🚀🚀oclint分析数据生成完毕🚀🚀🚀🚀🚀'$COLOR_SUCC
    else
    echo -e $COLOR_ERR'❌❌❌oclint分析数据生成失败❌❌❌'$COLOR_ERR
    return -1
    fi
  
}

oclintForProject $1


OCLint的不足之处

OCLint可以检测出来许许多多代码不规范的地方,这些不规范会影响代码的可读性问题,不易于维护,时间长了会造成很多技术债,但是更深层次的问题比如资源泄漏,内存泄漏这类问题OCLint是无法检测出来的,需要借助其他工具,比如FacebookInfer,这个放到下一篇再去分享。

上一篇 下一篇

猜你喜欢

热点阅读