目的:
总所周知,优雅的代码结构,可以使代码结构更清晰,维护更方便。但,不是团队的每一个成员都有如此编写习惯,在codereview的时候可能需要人为去审核提出建议。这样做人力成本大。而此脚本急速oclint自定义检查校验长函数的动态库脚本。
思路剖析:
1.寻找AST函数定义,分为VisitObjCMethodDecl与VisitFunctionDecl,其中VisitObjCMethodDecl为oc方法定义,VisitFunctionDecl为c函数定义。
2.访问到函数定义后可根据Stmt和文件管理器SourceManager计算出该函数的带代码总个数
class LongMethodRule : public AbstractASTVisitorRule<LongMethodRule>
{
private:
void applyDecl(Decl *decl)
{
//hasBody函数有实现内容吗
if (decl->hasBody() &&
!isCppMethodDeclLocatedInCppRecordDecl(dyn_cast<CXXMethodDecl>(decl)))
{
//有实现
Stmt *stmt = decl->getBody();
//计算函数里面代码总长度,getLineCount为帮助函数,后面有其方法
int length = getLineCount(stmt->getSourceRange(), _carrier->getSourceManager());
//oclint自身配置的长度可以调整修改
int threshold = RuleConfiguration::intForKey("LONG_METHOD", 50);
if (length > threshold)
{
//告警
string description = "Method with " +
toString<int>(length) + " lines exceeds limit of " + toString<int>(threshold);
addViolation(decl, this, description);
}
}
}
public:
virtual const string name() const override
{
return "long method";
}
virtual int priority() const override
{
return 3;
}
virtual const string category() const override
{
return "size";
}
#ifdef DOCGEN
virtual const std::string since() const override
{
return "0.4";
}
virtual const std::string description() const override
{
return "Long method generally indicates that this method tries to do many things. "
"Each method should do one thing and that one thing well.";
}
virtual const std::string example() const override
{
return R"rst(
.. code-block:: cpp
void example()
{
cout << "hello world";
cout << "hello world";
// repeat 48 times
}
)rst";
}
virtual const std::map<std::string, std::string> thresholds() const override
{
std::map<std::string, std::string> thresholdMapping;
thresholdMapping["LONG_METHOD"] =
"The long method reporting threshold, default value is 50.";
return thresholdMapping;
}
#endif
//oc函数:如果ViewController里面的- (void)viewDidLoad
bool VisitObjCMethodDecl(ObjCMethodDecl *decl)
{
applyDecl(decl);
return true;
}
//c函数的函数定义,eg:void testMyFunction(){***}
bool VisitFunctionDecl(FunctionDecl *decl)
{
applyDecl(decl);
return true;
}
};
static RuleSet rules(new LongMethodRule());
帮助函数:总行数
int getLineCount(clang::SourceRange sourceRange, const clang::SourceManager& sourceManager)
{
clang::SourceLocation startLocation = sourceRange.getBegin();
clang::SourceLocation endLocation = sourceRange.getEnd();
unsigned startLineNumber = sourceManager.getPresumedLineNumber(startLocation);
unsigned endLineNumber = sourceManager.getPresumedLineNumber(endLocation);
return endLineNumber - startLineNumber + 1;
}