OCLint规则说明

Anyhong 2019年08月08日 710次浏览

Introduction

依赖 OCLint 0.13 版本,共计71条rule。

字段说明:

  • Since:规则生效版本
  • Name:规则名称

Rule Index

Basic

BitwiseOperatorInConditional

Since: 0.6

Name: bitwise operator in conditional

检查条件语句中的位操作。虽然在一些情况下是故意编写的,但是位操作被认为太”巧妙”了。太巧妙的代码不太容易被理解。

规则定义文件: oclint-rules/rules/basic/BitwiseOperatorInConditionalRule.cpp

示例:


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

BrokenNullCheck

Since: 0.7

Name: broken null check

错误的 null 检查会导致程序 crash。

规则定义文件: oclint-rules/rules/basic/BrokenNullCheckRule.cpp

示例:


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

    if (a == NULL && a->bar(b))
    {
    }
}

BrokenNilCheck

Since: 0.7

Name: broken nil check

Objective-C 中判空操作,在有些情况下会返回预期相反的结果。

规则定义文件: oclint-rules/rules/basic/BrokenNullCheckRule.cpp

示例:


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

    if (!obj1 && ![obj1 isEqualTo:obj2])
    {
    }
}

BrokenOddnessCheck

Since: 0.6

Name: broken oddness check

使用 x % 2 == 1 进行奇数检查,如果是负数会不正常,应该使用 x & 1 == 1 或者 x % 2 != 0 这种方式。

规则定义文件: oclint-rules/rules/basic/BrokenOddnessCheckRule.cpp

示例:


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

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

CollapsibleIfStatements

Since: 0.6

Name: collapsible if statements

两个连续if语句可以合并为一个,以提高代码的简洁和可读性。

规则定义文件: oclint-rules/rules/basic/CollapsibleIfStatementsRule.cpp

示例:


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

ConstantConditionalOperator

Since: 0.6

Name: constant conditional operator

条件运算符的条件永远为真或永远为假是令人困惑的。

规则定义文件: oclint-rules/rules/basic/ConstantConditionalOperatorRule.cpp

示例:


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

ConstantIfExpression

Since: 0.2

Name: constant if expression

if条件语句永远为真或永远为假是令人困惑的

规则定义文件: oclint-rules/rules/basic/ConstantIfExpressionRule.cpp

示例:


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

DeadCode

Since: 0.4

Name: dead code

return、break、continue 和 throw 语句之后的代码是不可达的,永远不会执行。

规则定义文件: oclint-rules/rules/basic/DeadCodeRule.cpp

示例:


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

DoubleNegative

Since: 0.6

Name: double negative

使用双重否定没有意义,它总是正向的。

规则定义文件: oclint-rules/rules/basic/DoubleNegativeRule.cpp

示例:


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

ForLoopShouldBeWhileLoop

Since: 0.6

Name: for loop should be while loop

在某些情况下,可以将一些 for 循环简化为 while 循环,以使代码更简洁。

规则定义文件: oclint-rules/rules/basic/ForLoopShouldBeWhileLoopRule.cpp

示例:


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

GotoStatement

Since: 0.6

Name: goto statement

goto 语句不利于逻辑连贯性。

规则定义文件: oclint-rules/rules/basic/GotoStatementRule.cpp

示例:


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

References:

Edsger Dijkstra (March 1968). “Go To Statement Considered Harmful”. Communications of the ACM (PDF) 11 (3): 147–148. doi:10.1145/362929.362947.

JumbledIncrementer

Since: 0.7

Name: jumbled incrementer

混乱的增量通常是输入手误,如果是故意这样做的,那么这样的代码会让读者感到非常困惑。

规则定义文件: oclint-rules/rules/basic/JumbledIncrementerRule.cpp

示例:


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

MisplacedNullCheck

Since: 0.7

Name: misplaced null check

空指针检查放在错误的位置,空指针检查应该放在最前面。在C和c++中,向空指针发送消息可能会导致程序崩溃。当空指针检查放错位置时,要么检查无效,要么检查不正确。

规则定义文件: oclint-rules/rules/basic/MisplacedNullCheckRule.cpp

示例:


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

    if (a->bar(b) || !a)        // violation
    {
    }
}

MisplacedNilCheck

Since: 0.7

Name: misplaced nil check

空指针检查在 Objective-C 中,向空指针发送消息是没有任何作用的,但是代码读者可能会对放错位置的空指针检查操作感到困惑。

规则定义文件: oclint-rules/rules/basic/MisplacedNullCheckRule.cpp

示例:


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

    if (![obj1 isEqualTo:obj2] || obj1 == nil)
    {
    }
}

MultipleUnaryOperator

Since: 0.6

Name: multiple unary operator

连续多重运算符不易理解,应该简化。

规则定义文件: oclint-rules/rules/basic/MultipleUnaryOperatorRule.cpp

示例:

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

ReturnFromFinallyBlock

Since: 0.6

Name: return from finally block

不建议在finally块中return。

规则定义文件: oclint-rules/rules/basic/ReturnFromFinallyBlockRule.cpp

示例:

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

ThrowExceptionFromFinallyBlock

Since: 0.6

Name: throw exception from finally block

在finally块中抛出异常可能会掩盖其他异常或代码缺陷。

规则定义文件: oclint-rules/rules/basic/ThrowExceptionFromFinallyBlockRule.cpp

示例:


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
    }
}

Cocoa

MissingHashMethod

Since: 0.8

Name: missing hash method

当重写 isEqual 方法时,也必须重写 hash 方法

规则定义文件: oclint-rules/rules/cocoa/ObjCVerifyIsEqualHashRule.cpp

示例:


@implementation BaseObject

- (BOOL)isEqual:(id)obj {
    return YES;
}

/*
- (int)hash is missing; If you override isEqual you must override hash too.
*/
@end

MissingCallToBaseMethod

Since: 0.8

Name: missing call to base method

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

规则定义文件: oclint-rules/rules/cocoa/ObjCVerifyMustCallSuperRule.cpp

示例:


@interface UIView (OCLintStaticChecks)
- (void)layoutSubviews __attribute__((annotate("oclint:enforce[base method]")));
@end

@interface CustomView : UIView
@end

@implementation CustomView

- (void)layoutSubviews {
    // [super layoutSubviews]; is enforced here
}

@end

CallingProhibitedMethod

Since: 0.10.1

Name: calling prohibited method

当一个方式使用__attribute__((annotate("oclint:enforce[prohibited method]"))) 注解时, 它的所有用法都将被禁止。

规则定义文件: oclint-rules/rules/cocoa/ObjCVerifyProhibitedCallRule.cpp

示例:


@interface A : NSObject
- (void)foo __attribute__((annotate("oclint:enforce[prohibited method]")));
@end

@implementation A
- (void)foo {
}
- (void)bar {
    [self foo]; // calling method `foo` is prohibited.
}
@end

CallingProtectedMethod

Since: 0.8

Name: calling protected method

在 Objective-C 中虽然没有 protected 这个作用范围概念。但在设计的角度,我们有时候希望一个方法只被它自己或者它的子类调用。下面示例中这个方法可以模仿 protected,在有人调用保护方法的时候给出一个警告。

规则定义文件: oclint-rules/rules/cocoa/ObjCVerifyProtectedMethodRule.cpp

示例:


@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

MissingAbstractMethodImplementation

Since: 0.8

Name: missing abstract method implementation

由于 Objective-C 的 runtime 特性,决策尽可能推迟到运行时,所以抽象方法可以被声明,但是没有被实现,该规则用来验证子类是否正确实现抽象方法。

规则定义文件: oclint-rules/rules/cocoa/ObjCVerifySubclassMustImplementRule.cpp

示例:


@interface Parent

- (void)anAbstractMethod __attribute__((annotate("oclint:enforce[abstract method]")));

@end

@interface Child : Parent
@end

@implementation Child

/*
// Child, as a subclass of Parent, must implement anAbstractMethod
- (void)anAbstractMethod {}
*/

@end

Convention

AvoidBranchingStatementAsLastInLoop

Since: 0.7

Name: avoid branching statement as last in loop

在循环中使用分支语句作为最后一个语句是非常令人困惑的,并且可能很大程度上会忘记一些东西从而导致bug。

规则定义文件: oclint-rules/rules/convention/AvoidBranchingStatementAsLastInLoopRule.cpp

示例:


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

ProblematicBaseClassDestructor

Since: 0.10.2

Name: base class destructor should be virtual or protected

基类的析构函数需要是 public、virtual 或者 protected、nonvirtual。

规则定义文件: oclint-rules/rules/convention/BaseClassDestructorShouldBeVirtualOrProtectedRule.cpp

示例:


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

References:

Sutter & Alexandrescu (November 2004). “C++ Coding Standards: 101 Rules, Guidelines, and Best Practices”. Addison-Wesley Professional

UnnecessaryDefaultStatement

Since: 0.8

Name: unnecessary default statement in covered switch statement

当 switch 语句覆盖所有可能的情况时,不需要 default 标签,应该删除它。如果 switch 语句没有完全覆盖所有情况,SwitchStatementsShouldHaveDefault 规则将检测出这种情况。

规则定义文件: oclint-rules/rules/convention/CoveredSwitchStatementsDontNeedDefaultRule.cpp

示例:


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.
    }
}

MisplacedDefaultLabel

Since: 0.6

Name: ill-placed default label in switch statement

switch 语句中 default 标签不要乱放位置,应该放在最后一个分支位置。

规则定义文件: oclint-rules/rules/convention/DefaultLabelNotLastInSwitchStatementRule.cpp

示例:


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

DestructorOfVirtualClass

Since: 0.8

Name: destructor of virtual class

虚拟类的析构函数必须是虚拟的。

规则定义文件: oclint-rules/rules/convention/DestructorOfVirtualClassRule.cpp

示例:


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
};

InvertedLogic

Since: 0.4

Name: inverted logic

颠倒的逻辑不易理解,做逻辑判断的时候,最好先做 true 判断,再做 false 判断。

规则定义文件: oclint-rules/rules/convention/InvertedLogicRule.cpp

示例:


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;
}

MissingBreakInSwitchStatement

Since: 0.6

Name: missing break in switch statement

switch 语句中缺失了 break,很大可能引发bug。

规则定义文件: oclint-rules/rules/convention/MissingBreakInSwitchStatementRule.cpp

示例:


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

NonCaseLabelInSwitchStatement

Since: 0.6

Name: non case label in switch statement

当 label 成为 switch 语句的一部分时,这是非常令人困惑的。

规则定义文件: oclint-rules/rules/convention/NonCaseLabelInSwitchStatementRule.cpp

示例:


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

AssignIvarOutsideAccessors

Since: 0.8

Name: ivar assignment outside accessors or init

此规则禁止在 getter、setter 和 init 方法之外赋值 ivar。

规则定义文件: oclint-rules/rules/convention/ObjCAssignIvarOutsideAccessorsRule.cpp

示例:


@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

ParameterReassignment

Since: 0.6

Name: parameter reassignment

在大多数情况下,请不要对参数从新赋值直接使用,如果参数是指针,对指针重新赋值是可以的。

规则定义文件: oclint-rules/rules/convention/ParameterReassignmentRule.cpp

示例:


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

PreferEarlyExit

Since: 0.8

Name: prefer early exits and continue

做更早的逻辑退出判断,这样就不用记住所有的条件,更容易理解代码。

规则定义文件: oclint-rules/rules/convention/PreferEarlyExitRule.cpp

示例:


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 ....
}

MissingDefaultStatement

Since: 0.6

Name: missing default in switch statements

switch 语句应该有一个 default 语句。

规则定义文件: oclint-rules/rules/convention/SwitchStatementsShouldHaveDefaultRule.cpp

示例:


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

TooFewBranchesInSwitchStatement

Since: 0.6

Name: too few branches in switch statement

为了提高代码可读性,当一个 switch 只包含几个分支时,最好使用 if 语句代替。

规则定义文件: oclint-rules/rules/convention/TooFewBranchesInSwitchStatementRule.cpp

示例:


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
    switch语句中case语句计数的报告阈值,默认值为3。

Design

AvoidDefaultArgumentsOnVirtualMethods

Since: 0.10.1

Name: avoid default arguments on virtual methods

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

规则定义文件: oclint-rules/rules/design/AvoidDefaultArgumentsOnVirtualMethodsRule.cpp

示例:


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!

AvoidPrivateStaticMembers

Since: 0.10.1

Name: avoid private static members

避免使用私有静态成员,静态成员很容易破换封装性。

规则定义文件: oclint-rules/rules/design/AvoidPrivateStaticMembersRule.cpp

示例:


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

Empty

EmptyCatchStatement

Since: 0.6

Name: empty catch statement

捕捉了异常,但任何处理都没做。

规则定义文件: oclint-rules/rules/empty/EmptyCatchStatementRule.cpp

示例:


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

EmptyDoWhileStatement

Since: 0.6

Name: empty do/while statement

do-while 语句内不执行任何操作。

规则定义文件: oclint-rules/rules/empty/EmptyDoWhileStatementRule.cpp

示例:


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

EmptyElseBlock

Since: 0.6

Name: empty else block

else 语句不执行任何操作。

规则定义文件: oclint-rules/rules/empty/EmptyElseBlockRule.cpp

示例:


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

EmptyFinallyStatement

Since: 0.6

Name: empty finally statement

finally 语句不执行任何操作。

规则定义文件: oclint-rules/rules/empty/EmptyFinallyStatementRule.cpp

示例:


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

EmptyForStatement

Since: 0.6

Name: empty for statement

for 语句不执行任何操作。

规则定义文件: oclint-rules/rules/empty/EmptyForStatementRule.cpp

示例:


void example(NSArray *array)
{
    for (;;)  // empty for statement
    {
    }

    for (id it in array) // empty for-each statement
    {
    }
}

EmptyIfStatement

Since: 0.2

Name: empty if statement

做了条件判断但是没做任何操作。

规则定义文件: oclint-rules/rules/empty/EmptyIfStatementRule.cpp

示例:


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

EmptySwitchStatement

Since: 0.6

Name: empty switch statement

switch 语句不执行任何操作。

规则定义文件: oclint-rules/rules/empty/EmptySwitchStatementRule.cpp

示例:


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

EmptyTryStatement

Since: 0.6

Name: empty try statement

try 语句为空

规则定义文件: oclint-rules/rules/empty/EmptyTryStatementRule.cpp

示例:


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

EmptyWhileStatement

Since: 0.6

Name: empty while statement

while 语句不执行任何操作。

规则定义文件: oclint-rules/rules/empty/EmptyWhileStatementRule.cpp

示例:


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

Migration

UseBoxedExpression

Since: 0.7

Name: use boxed expression

使用字面量语法代替箱式表达式

规则定义文件: oclint-rules/rules/migration/ObjCBoxedExpressionsRule.cpp

示例:


void aMethod()
{
    NSNumber *fortyTwo = [NSNumber numberWithInt:(43 - 1)];
    // NSNumber *fortyTwo = @(43 - 1);

    NSString *env = [NSString stringWithUTF8String:getenv("PATH")];
    // NSString *env = @(getenv("PATH"));
}

UseContainerLiteral

Since: 0.7

Name: use container literal

使用字面量语法创建数组和字典

规则定义文件: oclint-rules/rules/migration/ObjCContainerLiteralsRule.cpp

示例:


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 };
}

UseNumberLiteral

Since: 0.7

Name: use number literal

使用字面量语法创建 NSNumber

规则定义文件: oclint-rules/rules/migration/ObjCNSNumberLiteralsRule.cpp

示例:


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

    NSNumber *yesBool = [NSNumber numberWithBool:YES];
    // NSNumber *yesBool = @YES;
}

UseObjectSubscripting

Since: 0.7

Name: use object subscripting

使用字面量语法获取数组指定索引对象或者获取字典指定key的value

规则定义文件: oclint-rules/rules/migration/ObjCObjectSubscriptingRule.cpp

示例:


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

    id item = [d objectForKey:@1];
    // id item = d[@1];
}

Naming

LongVariableName

Since: 0.7

Name: long variable name

变量名称太长

规则定义文件: oclint-rules/rules/naming/LongVariableNameRule.cpp

示例:


void aMethod()
{
    int reallyReallyLongIntegerName;
}

Thresholds:

  • LONG_VARIABLE_NAME
    长变量名报告阈值,默认值为20。

ShortVariableName

Since: 0.7

Name: short variable name

变量名称太短

规则定义文件: oclint-rules/rules/naming/ShortVariableNameRule.cpp

示例:


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

Thresholds:

  • SHORT_VARIABLE_NAME
    短变量名称报告阈值,默认值为3。

Redundant

RedundantConditionalOperator

Since: 0.6

Name: redundant conditional operator

此规则检测三种类型的冗余条件运算符:

  • true 表达式和f alse 表达式分别返回 true/false 和 false/true;
  • true 表达式和 false 表达式是相同的常数;
  • true 表达式和 false 表达式是同一个变量表达式;
    应该加以简化。

规则定义文件: oclint-rules/rules/redundant/RedundantConditionalOperatorRule.cpp

示例:


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;
}

RedundantIfStatement

Since: 0.4

Name: redundant if statement

不必要的 if 语句

规则定义文件: oclint-rules/rules/redundant/RedundantIfStatementRule.cpp

示例:


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;
}

RedundantLocalVariable

Since: 0.4

Name: redundant local variable

变量声明之后立即返回该变量,变量声明可以省略,直接尾调返回

规则定义文件: oclint-rules/rules/redundant/RedundantLocalVariableRule.cpp

示例:


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

RedundantNilCheck

Since: 0.7

Name: redundant nil check

在Objective-C中,像foo != nil && [foo bar]这样的 c/c++风格的null检查是多余的,因为在这种情况下,向nil对象发送消息只会返回false。

规则定义文件: oclint-rules/rules/redundant/RedundantNilCheckRule.cpp

示例:


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

UnnecessaryElseStatement

Since: 0.6

Name: unnecessary else statement

如果一个 if 语句块以一个 return 语句结束,或者 if 语句块中的所有分支都以 return 语句结束,那么 else 语句就没有必要了,else 语句中的代码可以在不位于块中的情况下运行。

规则定义文件: oclint-rules/rules/redundant/UnnecessaryElseStatementRule.cpp

示例:


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."
    }                           //
}

UnnecessaryNullCheckForDealloc

Since: 0.8

Name: unnecessary null check for dealloc

不必要的判空检查,在 dealloc 中 char* p = 0; delete p; 是有效的。

规则定义文件: oclint-rules/rules/redundant/UnnecessaryNullCheckForCXXDeallocRule.cpp

示例:


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

UselessParentheses

Since: 0.6

Name: useless parentheses

无用的括号。

规则定义文件: oclint-rules/rules/redundant/UselessParenthesesRule.cpp

示例:


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

Size

HighCyclomaticComplexity

Since: 0.4

Name: high cyclomatic complexity

圈复杂度由程序源代码中线性无关路径的数量决定。换句话说,方法的圈复杂度是由决策点的数量来度量的,比如 if、while 和 for 语句的数量,以及方法条目的数量。

圈复杂度的作者 McCabe 通过实验得出结论,复杂度在 3 到 7 之间的方法结构会非常好。他还建议圈复杂度为 10 是一个合理的上限。

规则定义文件: oclint-rules/rules/size/CyclomaticComplexityRule.cpp

示例:


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
    圈复杂度报告阈值,默认值为10。

Suppress:

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

References:

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

LongClass

Since: 0.6

Name: long class

类代码行数过多

规则定义文件: oclint-rules/rules/size/LongClassRule.cpp

示例:


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

Thresholds:

  • LONG_CLASS
    类大小报告阈值,默认值为1000。

LongLine

Since: 0.6

Name: long line

单行代码太长,影响可读性,应该折行

规则定义文件: oclint-rules/rules/size/LongLineRule.cpp

示例:


void example()
{
    int a012345678901234567890123456789...1234567890123456789012345678901234567890123456789;
}

Thresholds:

  • LONG_LINE
    长行报告阈值,默认值为100。

LongMethod

Since: 0.4

Name: long method

单个方法中代码行数太多

规则定义文件: oclint-rules/rules/size/LongMethodRule.cpp

示例:


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

Thresholds:

  • LONG_METHOD
    长方法报告阈值,默认值为50。

HighNcssMethod

Since: 0.6

Name: high ncss method

该规则通过计算非注释源语句(NCSS)来计算方法的行数。NCSS 只考虑实际语句,即忽略空语句、空块、右括号或右括号后的分号。与此同时,被分成多行的语句只贡献一个计数。

规则定义文件: oclint-rules/rules/size/NcssMethodCountRule.cpp

示例:


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

Thresholds:

  • NCSS_METHOD
    高NCSS方法报告阈值,默认值为30。

Suppress:

__attribute__((annotate("oclint:suppress[high ncss method]")))

DeepNestedBlock

Since: 0.6

Name: deep nested block

块或复合语句嵌套深度太大。

规则定义文件: oclint-rules/rules/size/NestedBlockDepthRule.cpp

示例:


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

Thresholds:

  • NESTED_BLOCK_DEPTH
    块或复合语句的深度报告阈值,默认值为5。

HighNPathComplexity

Since: 0.4

Name: high npath complexity

NPath 复杂度由该方法的执行路径数量决定。与圈复杂度相比,NPath复杂度有两个突出特点:一是区分了不同类型的控制流结构;其次,它考虑流图中各种类型的非循环路径。

基于作者在AT&T贝尔实验室的研究,建立了一种 NPath 阈值为 200 的方法。

规则定义文件: oclint-rules/rules/size/NPathComplexityRule.cpp

示例:


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

Thresholds:

  • NPATH_COMPLEXITY
    NPath复杂度报告阈值,默认值为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

TooManyFields

Since: 0.7

Name: too many fields

字段太多的类表示它做的事情太多,缺乏适当的抽象,可以将其重新设计得字段更少。

规则定义文件: oclint-rules/rules/size/TooManyFieldsRule.cpp

示例:


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

    void m() {}
};

Thresholds:

  • TOO_MANY_FIELDS
    对于太多字段的报告阈值,默认值为20。

TooManyMethods

Since: 0.7

Name: too many methods

方法太多的类表示它做的事情太多,很难阅读和理解,它通常包含复杂的代码,应该重构。

规则定义文件: oclint-rules/rules/size/TooManyMethodsRule.cpp

示例:


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();
};

Thresholds:

  • TOO_MANY_METHODS
    对于太多方法的报告阈值,默认值为30。

TooManyParameters

Since: 0.7

Name: too many parameters

参数太多的方法很难理解和维护,需要重构。比如用方法替换参数、引入参数对象或保存整个对象。

规则定义文件: oclint-rules/rules/size/TooManyParametersRule.cpp

示例:


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)
{
}

Thresholds:

  • TOO_MANY_PARAMETERS
    对于太多参数的报告阈值,默认值为10。

References:

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

Unused

UnusedLocalVariable

Since: 0.4

Name: unused local variable

声明但未使用的局部变量。

规则定义文件: oclint-rules/rules/unused/UnusedLocalVariableRule.cpp

示例:

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

消除:

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

UnusedMethodParameter

Since: 0.4

Name: unused method parameter

方法中未使用的参数。

规则定义文件: oclint-rules/rules/unused/UnusedMethodParameterRule.cpp

示例:

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

消除:

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