OC代码静态分析工具

简介

Xcode 自带的静态分析工具 Analyze,通过静态语法分析能够找出在代码层面就能发现的内存泄露问题,还可以通过上下文分析出是否存在变量无用等问题。但是,Analyze 的功能还是有限,还是无法帮助我们在编写代码的阶段发现更多的问题。所以,这才诞生出了功能更全、定制化高、效率高的第三方静态检查工具。比如,OCLint、Infer、Clang 静态分析器等。

静态分析器可以检查代码规范和代码可维护性的问题,根据一些指标就能够找出哪些代码需要优化和重构。这里有三个常用的复杂度指标,可以帮助我们度量是否需要优化和重构代码。

  • 圈复杂度高。

    圈复杂度,指的是遍历一个模块时的复杂度,这个复杂度是由分支语句比如 if、case、while、for,还有运算符比如 &&、||,以及决策点,共同确定的。一般来说,圈复杂度在以 4 以内是低复杂度,5 到 7 是中复杂度,8 到 10 是高复杂度,11 以上时复杂度就非常高了,这时需要考虑重构,不然就会因为测试用例的数量过高而难以维护。
    而这个圈复杂度的值,是很难通过人工分析出来的。而静态分析器就可以根据圈复杂度规则,来监控圈复杂度,及时发现代码是否过于复杂,发现问题后及早解决,以免造成代码过于复杂难以维护。

  • NPath 复杂度高。

    NPath 度量是指一个方法所有可能执行的路径数量。一般高于 200 就需要考虑降低复杂度了。

  • NCSS 度量高。

    NCSS 度量是指不包含注释的源码行数,方法和类过大会导致代码维护时阅读困难,大的 NCSS 值表示方法或类做的事情太多,应该拆分或重构。一般方法行数不过百,类的行数不过千。

但是,使用静态分析技术来保证工程质量,也并不尽如人意,还有如下两大缺陷:

  • 需要耗费更长的时间。

    相比于编译过程,使用静态分析技术发现深层次程序错误时,会对当前分析的方法、参数、变量去和整个工程关联代码一起做分析。所以,随着工程代码量的增加,每一步分析所依赖的影响面都会增大,所需耗时就更长。

    虽然我们在设计静态分析器时,就已经对其速度做了很多优化,但还是达不到程序编译的速度。因为静态分析本身就包含了编译最耗时的 IO 和语法分析阶段,而且静态分析的内容多于编译,所以再怎么优化,即使是最好的情况也会比编译过程来得要慢。

  • 静态分析器只能检查出那些专门设计好的、可查找的错误。

    对于特定类型的错误分析,还需要开发者靠自己的能力写一些插件并添加进去。
    好了,现在我们已经了解了静态分析器的优缺点,那么面对繁多的 iOS 的静态代码检查工具,我们到底应该选择哪一个呢?

OCLint

OCLint 是基于 Clang Tooling 开发的静态分析工具,主要用来发现编译器检查不到的那些潜在的关键技术问题。2017 年 9 月份新发布的 OCLint 0.13 版本中,包含了 71 条规则。

这些规则已经基本覆盖了具有通用性的规则,主要包括语法上的基础规则、Cocoa 库相关规则、一些约定俗成的规则、各种空语句检查、是否按新语法改写的检查、命名上长变量名短变量名检查、无用的语句变量和参数的检查。

除此之外,还包括了和代码量大小是否合理相关的一些规则,比如过大的类、类里方法是否太多、参数是否过多、Block 嵌套是否太深、方法里代码是否过多、圈复杂度的检查等。

Clang 静态分析器

Clang 静态分析器(Clang Static Analyzer)是一个用 C++ 开发的,用来分析 C、C++ 和 Objective-C 的开源工具,是 Clang 项目的一部分,构建在 Clang 和 LLVM 之上。Clang 静态分析器的分析引擎用的就是 Clang 的库。

Clang 静态分析器专门为速度做过优化,可以在保证查出错误的前提下,使用更聪明的算法减少检查的工作量。

Infer

Infer 是 Facebook 开源的、使用 OCaml 语言编写的静态分析工具,可以对 C、Java 和 Objective-C 代码进行静态分析,可以检查出空指针访问、资源泄露以及内存泄露。