一 、准备开发环境
mac系统安装有Xcode,git,ruby(一般都会有),还有要会科学上网
在OCLint的github上clone下代码 https://github.com/oclint/oclint 。(不要下载官方网站的代码),目录如下:
├── README.md ├── oclint-core ├── oclint-driver ├── oclint-metrics ├── oclint-reporters ├── oclint-rules └── oclint-scripts
cd
进入oclint-scripts
文件加,执行./make
。大约30分钟后编译完成,大概过程是下载LLVM、clang的源代码,编译LLVM、clang与OCLint预计OCLint的默认规则。(如果通过官网下载的OCLint代码,执行make时会通过SVN下载LLVM的代码,然而即便我科学上网了还是总是下载不成功,建议直接同git上下载OCLint的源码)编译成功后就可以写规则并且编译执行了。为了方便,OCLint提供了一个叫
scaffoldRule
的脚本程序,它在oclint-rules
目录下。我们通过他传入要生成的规则名,级别,类型,脚本就会在目录oclint-rules/rules/custom/
自动帮我们生成一个模板代码,并且加入编译路径中。举个例子:# 生成一个名为HdwTestRule类型是ASTVisitor的规则模板 oclint-scripts/scaffoldRule HdwTestRule -t ASTVisitor
生成两个文件:
# CMakeLists.txt 是对规则HdwTestRule的编译描述,由make程序在编译时使用。HdwTestRule.cpp的内容之后再分析。 ├── custom │ ├── CMakeLists.txt │ └── HdwTestRule.cpp
接着就可以对新添加的内容进行编译了,不过相比于重新执行
oclint-scripts/make
来说有一个更加优雅的办法,就是将规则相关的内容整合成一个Xcode工程,并且我们的每个规则都是一个scheme,编译时可以只选择编译那个选择的规则生成对应的dylib。做饭很简单,OCLint工程使用CMakeLists
的方式维护各个文件的依赖关系,我们可以使用CMake自带的功能将这些CMakeLists生成一个xcodeproj
工程文件。but how?下面栗子:# 在OCLint源码目录下建立一个文件夹,我这里命名为oclint-xcoderules mkdir oclint-xcoderules cd oclint-xcoderules # 创建一个脚本(代码如下段),并执行它(我写的方便修改参数,其实里面就一句命令,直接执行也行)(PS:刚创建的文件是没有执行权限的,不要忘了chmod) ./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
于是我们就得到了xcode工程:
├── CMakeCache.txt ├── CMakeFiles ├── CMakeScripts ├── OCLINT_RULES.build ├── OCLINT_RULES.xcodeproj ├── cmake_install.cmake ├── create-xcode-rules.sh ├── lib ├── rules └── rules.dl
打开
OCLINT_RULES.xcodeproj
:选择自己的规则,编译,成功后就可以在Products下看到生成的dylib啦,想想还有点小激动呢
二、开发规则
上面准备环境的一些步骤其实都是来自对OCLint官网的总结,同样如何去写自定义的规则还是要去看文档 http://docs.oclint.org/en/stable/ ,甚至于还要看clang的文档 http://clang.llvm.org/docs/IntroductionToTheClangAST.html 。我这里只能给出一些小建议,大概就是如何123去完成自定义的规则,希望再你阅读完文档但是不知道如何下手的时候能够帮到忙。
《 寓言故事》
小明看了OCLint的官方文档,了解了一下clang AST的知识,并读了一些OCLint AST的源码,大概知道OCLint调用clang 的API把一个个源文件生成一个一个AST,然后遍历树中的每个节点传入各个规则的整个过程。然后小明按照与上面类似的步骤最终生成并打开了OCLINT_RULES.xcodeproj。他觉得最好的学习方式是先阅读OCLint给出的默认规则的代码,大概读了几个后他似有所悟,于是就打开了之前自定义自动生成的HdwTestRule.cpp
文件开始自己编写。
小明决定写一个规则用于检查代码中“含有self的block中没有使用strongify”的那些block。
小明打开HdwTestRule.cpp,他看到一大堆(大概有两千行)注释代码,类似于:
class MissingStrongifyInCatchSelfBlockRule : public AbstractASTVisitorRule<MissingStrongifyInCatchSelfBlockRule>
{
/* Visit NullStmt
bool VisitNullStmt(NullStmt *node)
{
return true;
}
*/
/* Visit CompoundStmt
bool VisitCompoundStmt(CompoundStmt *node)
{
return true;
}
*/
/* Visit LabelStmt
bool VisitLabelStmt(LabelStmt *node)
{
return true;
}
*/
/* Visit AttributedStmt
bool VisitAttributedStmt(AttributedStmt *node)
{
return true;
}
*/
/* Visit IfStmt
bool VisitIfStmt(IfStmt *node)
{
return true;
}
*/
/* Visit SwitchStmt
bool VisitSwitchStmt(SwitchStmt *node)
{
return true;
}
*/
/* Visit WhileStmt
bool VisitWhileStmt(WhileStmt *node)
{
return true;
}
*/
}
小明嘴角微微一笑,因为他知道,就在上午他刚读过的OCLint的源码中表明这些以Visit开头的百十个函数都是OCLint提供给开发者的回调函数。小明机智的按下了command + f
输入了block
,结果他找到了两个回调:
bool VisitBlockExpr(BlockExpr *node)
{
return true;
}
bool VisitBlockDecl(BlockDecl *node)
{
return true;
}