袁凤鸣的博客 | Fleeming's Blog Front-end Dev Engineer

OCLint 的部分规则

2018-07-10
袁凤鸣


OCLint简介

OCLint简介

OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code and looking for potential problems like possible bugs, unused code, complicated code, redundant code, code smells, bad practices, and so on.

安装

$ brew tap oclint/formulae

$ brew install oclint

Using OCLint with xcodebuild

xcodebuild -target DemoProject -configuration Debug -scheme DemoProject

Using OCLint with xctool

安装

$ brew install xctool –HEAD

xctool -reporter json-compilation-database:compile_commands.json build

Using OCLint with xcpretty

安装

$ brew install xcpretty

xcodebuild [flags] | xcpretty -r json-compilation-database -o compile_commands.json

Using OCLint in Xcode

  • Add a new target in the project, and choose Aggregate as the template.


    图片名称

  • Name the new target, here we simply call it “OCLint”, you could have more than one targets that focus on different aspects of the code analysis.


图片名称

  • Add a new build phase in the target we just created. Choose Add Run Script for the phase type.


图片名称

  • Choose the correct build scheme, here we choose OCLint.Click to build, or use the shortcut Command+B.
  • Click to build, or use the shortcut Command+B.
  • When the progress bar scrolls to the very right, the analysis is done, then we can check out the analysis results same as compile warnings.


图片名称


OCLint规则 Basic 部分

1、bitwise operator in conditional

      since:0.6 定义类传送门~点击

Checks for bitwise operations in conditionals. Although being written on purpose in some rare cases, bitwise opera- tions are considered to be too “smart”. Smart code is not easy to understand.

简单解释:OCLint认为位运算符可读性不好

 void example(int a, int b) {
        if (a | b) {
        }
        if (a & b) {
        }
     }

2、broken null check

      since:0.7 定义类传送门~点击

The broken null check itself will crash the program.

简单解释:错误的null检查会导致程序crash

    void m(A *a, B *b) {
        if (a != NULL || a->bar(b))
        {
        }
        if (a == NULL && a->bar(b))
        {
        }
    }   

PS:OC(objective-c)向空对象可以发消息,不会发生crash,但是上面这样的代码的逻辑是错误的。

3、broken nil check

      since:0.7 定义类传送门~点击

The broken nil check in Objective-C in some cases returns just the opposite result.

简单解释:Objective-C中判空,有些情况下会返回预期相反的结果

    + (void)compare:(A *)obj1 withOther:(A *)obj2 {
        if (obj1 || [obj1 isEqualTo:obj2])
        {
        }
        if (!obj1 && ![obj1 isEqualTo:obj2])
        {
        }
    }

PS:这样写应该是逻辑错误

4、broken oddness check

      since:0.6 定义类传送门~点击

Checking oddness by x % 2 == 1won’t work for negative numbers. Use x & 1 == 1,or x % 2 != 0 instead.

简单解释:对数字奇数性进行检查(x % 2 == 1),如果是负数,会有异常,应使用x & 1 == 1或者x % 2 != 0

    void example() {
        if (x % 2 == 1)         // violation
        {
        }
        if (foo() % 2 == 1)     // violation
        {
        }
    }

PS:在Objective-C 上的测试结果上看,并没有什么大的异常。应该主要的问题是负数进行取模区的结果不会出现正值。
比如(x % 2)的结果是-1或者0

5、collapsible if statements

      Since: 0.6 定义类传送门~点击

This rule detects instances where the conditions of two consecutive if statements can be combined into one in order to increase code cleanness and readability.

简单解释:两个连续if条件可以合并的应该合并,可以提高可读性和代码整洁。

    void example(bool x, bool y){
        if (x)              // these two if statements can be
        {
            if (y)          // combined to if (x && y)
            {
                foo();
            }
        }
    }

6、constant conditional operator

      Since: 0.6 定义类传送门~点击

conditional operator whose conditionals are always true or always false are confusing.

简单解释:检查始终为true或者false的操作,会使人疑惑。

    void example() {
        int a = 1 == 1 ? 1 : 0;     // 1 == 1 is actually always true
    }

7、constant if expression

      Since: 0.2 定义类传送门~点击

if statements whose conditionals are always true or always false are confusing.

简单解释:if始终为true或者false的操作,会使人疑惑。

    void example(){
        if (true) {      // always true
            foo();
        }
        if (1 == 0) {    // always false
            bar();
        }
    }

8、 dead code

      Since: 0.4 定义类传送门~点击

Code after return, break, continue, and throw statements is unreachable and will never be executed.

简单解释:在 returnbreakcontinue and throw 之后的代码都是无效的

    void example(id collection) {
        for (id it in collection) {
            continue;
            int i1;                 // dead code
        }
        return;
        int i2;                     // dead code
    }

9、double negative

      Since:0.6 定义类传送门~点击

There is no point in using a double negative, it is always positive.

简单解释:代码中双重否定没有意义

    void example() {
        int b1 = !!1;
        int b2 = ~~1;
    }

10、for loop should be while loop

      Since:0.6 定义类传送门~点击

Under certain circumstances, some for loops can be simplified to while loops to make code more concise.

简单解释:在有些情况下使用while比使用for更简洁

    void example(int a) {
        for (; a < 100;) {
            foo(a);
        }
    }

11、 goto statement

      Since:0.6 定义类传送门~点击

Go To Statement Considered Harmful

简单解释:go to被认为有害的

    void example() {
        A:
            a();
        goto A;     // Considered Harmful
    }

12、jumbled incrementer

      Since:0.7 定义类传送门~点击

Jumbled incrementers are usually typos. If it’s done on purpose, it’s very confusing for code readers.

简单解释:混乱的迭代器通常会出现错误,可读性不好。

    void aMethod(int a) {
        for (int i = 0; i < a; i++) {
            for (int j = 0; j < a; i++) {     // references both 'i' and 'j'
            }
        }
    }

13、misplaced null check

      Since:0.7 定义类传送门~点击

The null check is misplaced. In C and C++, sending a message to a null pointer could crash the program. When null is misplaced, either the check is useless or it’s incorrect.

简单解释:CC++在条件判断的时候注意null判断放在前面,逻辑短路

    void m(A *a, B *b) {
        if (a->bar(b) && a != NULL) { // violation 
        }
        if (a->bar(b) || !a) {        // violation
        }
    }

14、misplaced nil check

      Since:0.7 定义类传送门~点击

The nil check is misplaced. In Objective-C, sending a message to a nil pointer simply does nothing. But code readers may be confused about the misplaced nil check.

简单解释:Objective-C在条件判断的时候注意nil判断放在前面,逻辑短路

    + (void)compare:(A *)obj1 withOther:(A *)obj2 {
        if ([obj1 isEqualTo:obj2] && obj1) {
        }
        if (![obj1 isEqualTo:obj2] || obj1 == nil)   {
        }
    }

15、 multiple unary operator

      Since:0.6 定义类传送门~点击

Multiple unary operator can always be confusing and should be simplified.

简单解释:多重的运算符不易理解,应该简化。

    void example() {
        int b = -(+(!(~1)));
    }

16、return from finally block

      Since:0.6 定义类传送门~点击

Returning from a finally block is not recommended.

简单解释:不建议在finally中返回

    void example() {
        @try {
            foo();
        }
        @catch(id ex) {
            bar();
        }
        @finally {
            return;         // this can discard exceptions.
        }
    }

17、throw exception from finally block

      Since:0.6 定义类传送门~点击

Throwing exceptions within a finally block may mask other exceptions or code defects.

简单解释:从finally块抛出异常,可能忽略其他的错误

    void example() {
        @try {;}
        @catch(id ex) {;}
        @finally {
            id ex1;
            @throw ex1;                              // this throws an exception
            NSException *ex2 = [NSException new];
            [ex2 raise];                             // this throws an exception, too
        }
    }

OCLint规则 Unuseed 部分

1、unused local variable

      Since:0.4 定义类传送门~点击

This rule detects local variables that are declared, but not used.

简单解释:有局部变量没有使用。

    int example(int a) {
        int i;          // variable i is declared, but not used
        return 0;
    }

Suppress:
__attribute__((annotate("oclint:suppress[unused local variable]")))

2、unused method parameter

      Since:0.4 定义类传送门~点击

This rule detects parameters that are not used in the method.

简单解释:方法参数没有被使用.

    int example(int a)  // parameter a is not used {
        return 0;
    }

Suppress:
__attribute__((annotate("oclint:suppress[unused method parameter]")))

OCLint规则 Size 部分

1、high cyclomatic complexity

      Since:0.4 定义类传送门~点击

Cyclomatic complexity is determined by the number of linearly independent paths through a program’s source code. In other words, cyclomatic complexity of a method is measured by the number of decision points, like if, while, and for statements, plus one for the method entry.

简单解释:圈复杂度过高。统计一个函数有多少个分支(if, while,for,等等),没有的话复杂度为一,每增加一个分支复杂度加一。简单计算的话V(G)=e-n+2。其中,e表示控制流图中边的数量,n表示控制流图中节点的数量,或者V(G)=区域数=判定节点数+1。当然可以数一数。

    void example(int a, int b, int c) { // 1
        if (a == b) {                   // 2
            if (b == c) {               // 3 
            } else if (a == c){          // 3
            }
            else {
            }
        }
        for (int i = 0; i < c; i++)  {  // 4
        }
        switch(c)  {
            case 1:                   // 5
                break;
            case 2:                   // 6
                break;
            default:                  // 7
                break;
        }
    }

Thresholds:
CYCLOMATIC_COMPLEXITY The cyclomatic complexity reporting threshold, default value is 10. Suppress:

Suppress:
__attribute__((annotate("oclint:suppress[high cyclomatic complexity]")))

References:
McCabe (December 1976). “A Complexity Measure”. IEEE Transactions on Software Engineering: 308–320

2、long class

      Since:0.6 定义类传送门~点击

Long class generally indicates that this class tries to do many things. Each class should do one thing and that one thing well.

简单解释:类行数太多。

    class Foo {
        void bar() {
            // 1001 lines of code
        }
    }

Thresholds:
LONG_CLASS The class size reporting threshold, default value is 1000.

3、 long line

      Since:0.6 定义类传送门~点击

When the number of characters for one line of code is very high, it largely harms the readability. Break long lines of code into multiple lines.

简单解释:单行代码太长,影响可读性。

    void example()
    {
        int a012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789;
    }

Thresholds:
LONG_LINE The long line reporting threshold, default value is 100.

4、long method

      Since:0.6 定义类传送门~点击

Long method generally indicates that this method tries to do many things. Each method should do one thing and that one thing well.

简单解释:方法太长,影响阅读,应该实现单一职责。

    void example() {
        cout << "hello world";
        cout << "hello world";
        // repeat 48 times
    }

Thresholds:
LONG_METHOD The long method reporting threshold, default value is 50.

5、 high ncss method

      Since:0.6 定义类传送门~点击

This rule counts number of lines for a method by counting Non Commenting Source Statements (NCSS). NCSS only takes actual statements into consideration, in other words, ignores empty statements, empty blocks, closing brackets or semicolons after closing brackets. Meanwhile, a statement that is broken into multiple lines contribute only one count.

简单解释:其实是指某个代码块中代码行数过多(只统计有效的语句),查看代码块中代码是否能拆分,公共功能能否提供一个公共接口。空语句,空块,右括号或分号后的右括号会被忽略。

    void example()          // 1
    {
        if (1)              // 2
        {
        }  else                // 3
        {
        }
    }

Thresholds:
NCSS_METHOD The high NCSS method reporting threshold, default value is 30.

Suppress:
attribute((annotate(“oclint:suppress[high ncss method]”)))

6、deep nested block

      Since:0.6 定义类传送门~点击

This rule indicates blocks nested more deeply than the upper limit.

简单解释:嵌套块是否超过指定的深度值.

    if (1) {               // 1
        {           // 2
            {       // 3
            }
        }
    }

Thresholds:
NESTED_BLOCK_DEPTH The depth of a block or compound statement reporting threshold, default value is 5.

7、high npath complexity

      Since:0.4 定义类传送门~点击

NPath complexity is determined by the number of execution paths through that method. Compared to cyclomatic complexity, NPath complexity has two outstanding characteristics: first, it distinguishes between different kinds of control flow structures; second, it takes the various type of acyclic paths in a flow graph into consideration.
Based on studies done by the original author in AT&T Bell Lab, an NPath threshold value of 200 has been established for a method.

简单解释:NPath复杂度是一个方法中各种可能的执行路径总和,一般把200作为考虑降低复杂度的临界点,这里提示NPath复杂度过高。

    void example() {
        // complicated code that is hard to understand
    }

Thresholds:
NPATH_COMPLEXITY The NPath complexity reporting threshold, default value is 200.

Suppress:
__attribute__((annotate("oclint:suppress[high npath complexity]")))

References:
Brian A. Nejmeh (1988). “NPATH: a measure of execution path complexity and its applications”. Communications of the ACM 31 (2) p. 188-200

8、too many fields

      Since:0.7 定义类传送门~点击

A class with too many fields indicates it does too many things and lacks proper abstraction. It can be redesigned to have fewer fields.

简单解释:一个类中有定义太多东西,需要进行适当的抽象、设计。

    class c {
        int a, b;
        int c;
        // ...
        int l;
        int m, n;
        // ...
        int x, y, z;
        void m() {}
    };

Thresholds:
TOO_MANY_FIELDS The reporting threshold for too many fields, default value is 20.

9、too many methods

      Since:0.7 定义类传送门~点击

A class with too many methods indicates it does too many things and is hard to read and understand. It usually contains complicated code, and should be refactored.

简单解释:一个类有太多的方法,证明他做了太多的事儿,不利于理解。应该考虑重构。考虑单一职责。

    class c {
        int a();
        int b();
        int c();
        // ...
        int l();
        int m();
        int n();
        // ...
        int x();
        int y();
        int z();
        int aa();
        int ab();
        int ac();
        int ad();
        int ae();
    };

10、too many parameters

      Since:0.7 定义类传送门~点击

Methods with too many parameters are hard to understand and maintain, and are thirsty for refactorings, like Replace Parameter With method, Introduce Parameter Object, or Preserve Whole Object.

简单解释: 一个方法中参数过多。

    void example(int a, int b, int c, int d, int e, int f,
        int g, int h, int i, int j, int k, int l) {
    }

TOO_MANY_PARAMETERS The reporting threshold for too many parameters, default value is 10.

References:
Fowler, Martin (1999). Refactoring: Improving the design of existing code. Addison Wesley.

OCLint规则 Redundant 部分

1、redundant conditional operator

      Since:0.6 定义类传送门~点击

This rule detects three types of redundant conditional operators:

  1. true expression and false expression are returning true/false or false/true respectively;
  2. true expression and false expression are the same constant;
  3. true expression and false expression are the same variable expression.

They are usually introduced by mistake, and should be simplified.

简单解释:冗余的条件判断会造成一些错误,应该让它变得简洁。

比如: 1.true对应truefalse对应false

           2 . true对应falsefalse对应true

           3 . truefalse一致。

    void example(int a, int b, int c) {
        bool b1 = a > b ? true : false;     // true/false: bool b1 = a > b;
        bool b2 = a > b ? false : true;     // false/true: bool b2 = !(a > b);
        int i1 = a > b ? 1 : 1;             // same constant: int i1 = 1;
        float f1 = a > b ? 1.0 : 1.00;      // equally constant: float f1 = 1.0;
        int i2 = a > b ? c : c;             // same variable: int i2 = c;
    }

2、redundant if statement

      Since:0.4 定义类传送门~点击

This rule detects unnecessary if statements.

简单解释:多余的if判断,可以省略。

    bool example(int a, int b) {
        if (a == b)             // this if statement is redundant
        {
            return true;
        }  else   {
            return false;
        }                       // the entire method can be simplified to return a == b;
    }

3、redundant local variable

      Since:0.4 定义类传送门~点击

This rule detects cases where a variable declaration is immediately followed by a return of that variable.

简单解释:冗余的局部变量,可以省略,直接return

    int example(int a) {
        int b = a * 2;
        return b;   // variable b is returned immediately after its declaration,
    }

4、redundant nil check

      Since:0.7 定义类传送门~点击

C/C++-style null check in Objective-C like foo != nil && [foo bar] is redundant, since sending a message to a nil object in this case simply returns a false-y value.

简单解释:在C或者C++中适用的判空检查在OC中是多余的。因为在OC中向空对象发送消息会返回false值。

    + (void)compare:(A *)obj1 withOther:(A *)obj2  {
        if (obj1 && [obj1 isEqualTo:obj2]) // if ([obj1 isEqualTo:obj2]) is okay   {
        }
    }

5、 unnecessary else statement

      Since:0.6 定义类传送门~点击

When an if statement block ends with a return statement, or all branches in the if statement block end with return statements, then the else statement is unnecessary. The code in the else statement can be run without being in the block.

简单解释:如果if中已经带有return,则不需要写else语句。

    bool example(int a) {
        if (a == 1)                 // if (a == 1)
        {                           // {
            cout << "a is 1.";      //     cout << "a is 1.";
            return true;            //     return true;
        }                           // }
        else                        //
        {                           //
            cout << "a is not 1."   // cout << "a is not 1."
        }                           //
    }

6、unnecessary null check for dealloc

      Since:0.8 定义类传送门~点击

char* p = 0; delete p;isvalid.Thisrulelocatesunnecessaryif (p)checks.

简单解释:在dealloc中不需要判空,就能Delete元素。

    void m(char* c) {
        if (c != nullptr) { // and be simplified to delete c;
            delete c;
        }
    }

7、 useless parentheses

      Since:0.6 定义类传送门~点击

This rule detects useless parentheses.

简单解释:检查无用的括号。

    int example(int a) {
        int y = (a + 1);    // int y = a + 1;
        if ((y > 0))        // if (y > 0)
        {
            return a;
        }
        return (0);         // return 0;
    }

PS:检测了一下在括号里是逻辑判断时不会被检测到,如下(不会被检查到):

    BOOL aaaa = YES;
    BOOL bbbb = NO;
     if((aaaa) && (bbbb)) {
        return YES;
      }

OCLint规则 Naming 部分

1、long variable name

      Since:0.7 定义类传送门~点击

Variables with long names harm readability.

简单解释:变量名较长,影响可读性。

    void aMethod() {
        int reallyReallyLongIntegerName;
    }

Thresholds:
LONG_VARIABLE_NAME The long variable name reporting threshold, default value is 20.

2、hort variable name

      Since:0.7 定义类传送门~点击

A variable with a short name is hard to understand what it stands for. Variable with name, but the name has number of characters less than the threshold will be emitted.

简单解释:变量名太短,影响可读性。

    void aMethod(int i)  // i is short
    {
        int ii;          // ii is short
    }

Thresholds:
SHORT_VARIABLE_NAME The short variable name reporting threshold, default value is 3.

OCLint规则 Migration 部分

1、use boxed expression

      Since:0.7 定义类传送门~点击

This rule locates the places that can be migrated to the new Objective-C literals with boxed expressions.

简单解释:建议使用新方法,快速创建(numberWithIntstringWithUTF8String:)。

    void aMethod() {
        NSNumber *fortyTwo = [NSNumber numberWithInt:(43 - 1)];
        // NSNumber *fortyTwo = @(43 - 1);
        NSString *env = [NSString stringWithUTF8String:getenv("PATH")];
        // NSString *env = @(getenv("PATH"));
    }

2、 use container literal

      Since:0.7 定义类传送门~点击

This rule locates the places that can be migrated to the new Objective-C literals with container literals.

简单解释:建议使用新方法,快速创建(arrayWithObjectsdictionaryWithObjects)。

    void aMethod()
    {
        NSArray *a = [NSArray arrayWithObjects:@1, @2, @3, nil];
        // NSArray *a = @[ @1, @2, @3 ];
        NSDictionary *d = [NSDictionary dictionaryWithObjects:@[@2,@4] forKeys:@[@1,@3]];
        // NSDictionary *d = @{ @1 : @2, @3 : @4 };
    }

3、use number literal

      Since:0.7 定义类传送门~点击

This rule locates the places that can be migrated to the new Objective-C literals with number literals.

简单解释:建议使用新方法,快速创建(numberWithIntnumberWithBOOL)。

    void aMethod() {
        NSNumber *fortyTwo = [NSNumber numberWithInt:42];
        // NSNumber *fortyTwo = @42;
        NSNumber *yesBool = [NSNumber numberWithBool:YES];
        // NSNumber *yesBool = @YES;
    }

4、use object subscripting

      Since:0.7 定义类传送门~点击

This rule locates the places that can be migrated to the new Objective-C literals with object subscripting.

简单解释:建议使用新方法,快速创建(objectAtIndexobjectForKey)。

    void aMethod(NSArray *a, NSDictionary *d) {
        id item = [a objectAtIndex:0];
        // id item = a[0];
        id item = [d objectForKey:@1];
        // id item = d[@1];
    }

OCLint规则 Empty 部分

1、empty catch statement

      Since:0.6 定义类传送门~点击

This rule detects instances where an exception is caught, but nothing is done about it.

简单解释:捕获了异常,在Catch中什么都没有做的情况。

    void example()  {
        try {
            int* m= new int[1000];
        }
        catch(...)                  // empty catch statement, this swallows an exception
        {
        }
    }

2、empty do/while statement

      Since:0.6 定义类传送门~点击

This rule detects instances where do-while statement does nothing.

简单解释:空的do-while检查。

    void example() {
        do
        {                           // empty do-while statement
        } while(1);
    }

3、empty else block

      Since:0.6 定义类传送门~点击

This rule detects instances where a else statement does nothing.

简单解释:空的else检查。

    int example(int a)  {
        if (1)  {
            return a + 1;
        }  else  {               // empty else statement, can be safely removed
        }
    }

4、empty finally statement

      Since:0.6 定义类传送门~点击

This rule detects instances where a finally statement does nothing.

简单解释:空的finally检查。

    void example() {
        Foo *foo;
        @try {
            [foo bar];
        }
        @catch(NSException *e) {
            NSLog(@"Exception occurred: %@", [e description]);
        }
        @finally            // empty finally statement, probably forget to clean up?
        {
        }
    }

5、empty for statement

      Since:0.6 定义类传送门~点击

This rule detects instances where a for statement does nothing.

简单解释:空的for语句检查。

    void example(NSArray *array) {
        for (;;)                // empty for statement
        {
        }
        for (id it in array)    // empty for-each statement
        {
        }
    }

6、empty if statement

      Since:0.2 定义类传送门~点击

This rule detects instances where a condition is checked, but nothing is done about it.

简单解释:空的if检查。

    void example(int a) {
        if (a == 1)                  // empty if statement
        {
        }
    }

7、empty switch statement

      Since:0.6 定义类传送门~点击

This rule detects instances where a switch statement does nothing.

简单解释:空的switch检查。

    void example(int i) {
        switch (i)              // empty switch statement
        {
        }
    }

8、empty try statement

      Since:0.6 定义类传送门~点击

This rule detects instances where a try statement is empty.

简单解释:空的try检查。

    void example() {
        try                     // but this try statement is empty
        {
        }
        catch(...) {
            cout << "Exception is caught!";
        }
    }

9、 empty while statement

      Since:0.6 定义类传送门~点击

This rule detects instances where a while statement does nothing.

简单解释:空的while检查。

    void example(int a {
        while(a--)              // empty while statement
        {
        }
    }

OCLint规则 Design 部分

1、avoid default arguments on virtual methods

      Since:0.10.1 定义类传送门~点击

Giving virtual functions default argument initializers tends to defeat polymorphism and introduce unnecessary com- plexity into a class hierarchy.

简单解释:避免给虚函数设置默认参数,给虚函数设置默认参数会破坏多样性和引起不必要的层次结构发杂性。

    class Foo
    {
    public:
        virtual ~Foo();
        virtual void a(int b = 3);
        // ...
    };
    class Bar : public Foo
    {
    public:
        void a(int b);
        // ...
    };
    Bar *bar = new Bar;
    Foo *foo = bar;
    foo->a();   // default of 3
    bar->a();   // compile time error!

2、avoid private static members

      Since:0.10.1 定义类传送门~点击

Having static members is easier to harm encapsulation.

简单解释:避免使用私有静态成员,静态成员很容易破换封装性

    class Foo {
        static int a;       // static field
    };
    class Bar {
        static int b();     // static method
    }

OCLint规则 Convention 部分

1、avoid branching statement as last in loop

      Since:0.7 定义类传送门~点击

Having branching statement as the last statement inside a loop is very confusing, and could largely be forgetting of something and turning into a bug.

简单解释:不要再循环最后加入分支,负责理解起来比较困难,很大程度上会遗忘一些事情,导致一些错误。

    void example() {
        for (int i = 0; i < 10; i++) {
            if (foo(i)) {
                continue;
            }
            break;      // this break is confusing
        }
    }

2、base class destructor should be virtual or protected

      Since:0.10.2 定义类传送门~点击

Make base class destructor public and virtual, or protected and nonvirtual

简单解释:基类的析构函数需要是publicvirtual或者protected``nonvirtual

    class Base {
    public:
        ~Base(); // this should be either protected or virtual
    }
    class C : public Base {
        virtual ~C();
    }

Sutter & Alexandrescu (November 2004). [“C++ Coding Standards: 101 Rules, Guidelines, and Best Practices”(http://gotw.ca/publications/c++cs.htm)]. Addison-Wesley Professional

3、unnecessary default statement in covered switch statement

      Since:0.8 定义类传送门~点击

When a switch statement covers all possible cases, a default label is not needed and should be removed. If the switch is not fully covered, the SwitchStatements Should Have Default rule will report.

简单解释:如果switch覆盖了所有的条件,default是不需要的应该被移除。如果不是default还是需要的。

    typedef enum {
        value1 = 0,
        value2 = 1
    } eValues;
    //
    void aMethod(eValues a)
    {
        switch(a)
        {
            case value1:
                break;
            case value2:
                break;
            default:          // this break is obsolete because all
                break;        // values of variable a are already covered.
        }
    }

4、 ill-placed default label in switch statement

      Since:0.6 定义类传送门~点击

It is very confusing when default label is not the last label in a switch statement.

简单解释:default应该在switch的最后,负责会很难理解。

    void example(int a) {
        switch (a) {
            case 1:
                break;
            default:  // the default case should be last
                break;
            case 2:
                break;
        }
    }

5、destructor of virtual class

      Since:0.8 定义类传送门~点击

This rule enforces the destructor of a virtual class must be virtual.

简单解释:这个规则是虚拟类的析构函数必须是虚拟的。

    class Base { // class Base should have a virtual destructor ~Base()
        public: virtual void f();
    };
    class Child : public Base {
        public: ~Child();  // destructor ~Child() should be virtual
    };

6、inverted logic

      Since:0.4 定义类传送门~点击

An inverted logic is hard to understand.

简单解释:倒置逻辑不易理解。

    int example(int a) {
        int i;
        if (a != 0)             // if (a == 0)
        {                       // {
            i = 1;              //      i = 0;
        }                       // }
        else                    // else
        {                       // {
            i = 0;              //      i = 1;
        }                       // }
        return !i ? -1 : 1;     // return i ? 1 : -1;
    }

PS:在做判断的时候,应该先做的判断,在做的判断。做个一个测试如果只有非的测试是不会有警告的。

    int example(int condition) {
        int temp;
        if (acondition!= 0)            //不会有警告
        {                       
            temp = 1;            
        }                  
    }

7、missing break in switch statement

      Since:0.6 定义类传送门~点击

A switch statement without a break statement has a very large chance to contribute a bug.

简单解释:在switch语句中缺失了break,很有可能引发bug

    void example(int a) {
        switch (a) {
            case 1:
                break;
            case 2:
                // do something
            default:
                break;
        }
    }

8、non case label in switch statement       Since:0.6 定义类传送门~点击

It is very confusing when label becomes part of the switch statement.

简单解释:label出现在switch条件中不易理解。

    void example(int a) {
        switch (a) {
            case 1:
                break;
            label1:     // label in a switch statement in really confusing
                break;
            default:
                break;
        }
    }

9、 ivar assignment outside accessors or init       Since:0.8 定义类传送门~点击

This rule prevents assigning an ivar outside of getters, setters, and init method.

简单解释:检查某些成员的初始化不再getterssetters andinit method中。

    @interface Foo : NSObject {
        int _bar;
    }
    @property (assign, nonatomic) int bar;
    @end
    @implementation Foo
    @synthesize bar = _bar;
    - (void)doSomething {
        _bar = 3; // access _bar outside its getter, setter or init
    }
    @end

PS:简单和小伙伴讨论了下,感觉iOS开发并不是很适合。

10、parameter reassignment       Since:0.6 定义类传送门~点击

Reassigning values to parameters is very problematic in most cases.

简单解释:对参数进行重新赋值,在很多情况下是有问题的。

    void example(int a) {
        if (a < 0) {
            a = 0; // reassign parameter a to 0
        }
    }

PS:简单测试了传值时使用指针,经测试不会有警告。也就是说不会对指针类型的参数做检查。

11、prefer early exits and continue       Since:0.8 定义类传送门~点击

Early exits can reduce the indentation of a block of code, so that reader do not have to remember all the previous decisions, therefore, makes it easier to understand the code.

简单解释:在有退出语句 的时候,应该让退出语句靠前,这样阅读代码使代码可以很好的被理解。

    int *doSomething(int a) {
      if (!foo(a) && bar(a) && doOtherThing(a)) {
        // ... some really long code ....
      }
      return 0;
    }
    // is preferred as
    int *doSomething(int a) {
      if (foo(a)) {
        return 0;
      }
      if (!bar(a)) {
        return 0;
      }
      if (!doOtherThing(a)) {
        return 0;
      }
      // ... some long code ....
    }

12、 missing default in switch statements       Since:0.6 定义类传送门~点击

Switch statements should have a default statement.

简单解释:检查 Switchdefault缺失的情况。

    void example(int a) {
        switch (a) {
            case 1:
                break;
            case 2:
                break;
            // should have a default
        }
    }

13、 too few branches in switch statement       Since:0.6 定义类传送门~点击

To increase code readability, when a switch consists of only a few branches, it’s much better to use an if statement instead.

简单解释:如果switch语句条件很少,可以一用if else 代替。

    void example(int a) {
        switch (a) {
            case 1:
                break;
            default:
                break;
        } // Better to use an if statement and check if variable a equals 1.
    }

Thresholds:
MINIMUM_CASES_IN_SWITCH The reporting threshold for count of case statements in a switch statement, de-
fault value is 3.

OCLint规则 CoCoa 部分

1、missing hash method

      Since:0.8 定义类传送门~点击

When isEqual method is overridden, hash method must be overridden, too.

简单解释:isEqual 方法被重写, hash 方法也应该被重写.

    @implementation BaseObject
    - (BOOL)isEqual:(id)obj {
        return YES;
    }
    /*
    - (int)hash is missing; If you override isEqual you must override hash too.
    */
    @end

2、missing call to base method

      Since:0.8 定义类传送门~点击

When a method is declared with attribute((annotate(“oclint:enforce[base method]”))) annotation, all of its implementations (including its own and its sub classes) must call the method implementation in super class.

简单解释:当使用 __attribute__((annotate("oclint:enforce[must call super]"))) 注解时, 他的所有实现(包括他自己和子类)都必须调用超类的实现

    @interface UIView (OCLintStaticChecks)
    - (void)layoutSubviews __attribute__((annotate("oclint:enforce[must call super]")));
    @end
    @interface CustomView : UIView
    @end
    @implementation CustomView
    - (void)layoutSubviews {
        // [super layoutSubviews]; is enforced here
    }
    @end

3、calling prohibited method

      Since:0.10.1 定义类传送门~点击

hen a method is declared with attribute((annotate(“oclint:enforce[prohibited method]”))) annotation, all of its usages will be prohibited.

简单解释:当一个方法标记__attribute__((annotate("oclint:enforce[prohibited call]")))注解,所有的引用都将被禁止。

    @interface A : NSObject
    - (void)foo __attribute__((annotate("oclint:enforce[prohibited call]")));
    @end
    @implementation A
    - (void)foo {
    }
    - (void)bar {
        [self foo]; // calling method `foo` is prohibited.
    }
    @end

4、calling protected method

      Since:0.8 定义类传送门~点击

Even though there is no protected in Objective-C language level, in a design’s perspective, we sometimes hope to enforce a method only be used inside the class itself or by its subclass. This rule mimics the protected behavior, and alerts developers when a method is called outside its access scope.

简单解释:在Objective-C 中虽然没有protected这个概念。但是在设计的角度,我们有时希望一个方法只希望被它自己或者它的子类调用。这个方法可以模仿protected在有人调用的时候给一个警告。

    @interface A : NSObject
    - (void)foo __attribute__((annotate("oclint:enforce[protected method]")));
    @end
    @interface B : NSObject
    @property (strong, nonatomic) A* a;
    @end
     //
    @implementation B
    - (void)bar {
        [self.a foo]; // calling protected method foo from outside A and its subclasses
    }
    @end

5、missing abstract method implementation

      Since:0.8 定义类传送门~点击

Due to the Objective-C language tries to postpone the decision makings to the runtime as much as possible, an abstract method is okay to be declared but without implementations. This rule tries to verify the subclass implement the correct abstract method.

简单解释:由于Objectiveruntime特性,抽象方法可以被声明,可以不实现,该规则验证子类是否正确实现抽象方法。

    @interface Parent
    //
    - (void)anAbstractMethod __attribute__((annotate("oclint:enforce[subclass must implement]")));
    //
    @end
    @interface Child : Parent
    @end
    //
    @implementation Child
    /*
    // Child, as a subclass of Parent, must implement anAbstractMethod
    - (void)anAbstractMethod {}
    */
    @end

参考资料:https://blog.csdn.net/foolsong/article/details/76474125
将上文中所有规则汇聚在一个页面中,方便搜索。



如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

¥ 打赏博主

请科学上网看评论 😂

Enjoy music ?
Search
    Content