OCLINT自定义规则-长函数限定LongMethodRule

2018-07-07  本文已影响0人  熊猫人和熊猫君

目的:

总所周知,优雅的代码结构,可以使代码结构更清晰,维护更方便。但,不是团队的每一个成员都有如此编写习惯,在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;
}
上一篇下一篇

猜你喜欢

热点阅读