当前位置: 首页 > 工具软件 > OCLint > 使用案例 >

[OCLint]OCLint代码检查规则

仲霍英
2023-12-01

OCLint 0.10.2 包含67条规则

Basic(基本)

  • BitWiseOperationInConditional (在条件语句中查找按位操作的条件、虽然这些操作都很“聪明”,但太聪明的语法很难理解 like:if (a | b)
  • BrokenNilCheck (nil检查 在某些情况会返回相反的结果 like:if (!obj1))
  • BrokenNullCheck (null检查会导致程序crash like:if (a == NULL)
  • BrokenOddnessCheck (x % 2 == 1 对于负数不起作用、使用 x & 1 == 1 or x % 2 != 0 代替)
  • CollapsibleIfStatements(检查是否两个情况可以合在一个条件中
 if (x)              // these two if statements can be
    {
        if (y)          // combined to if (x && y)
        {
            foo();
        }
    }`
  • ConstantConditionalOperator(是否条件永远true或者永远false like:int a = 1== 1 ? 1:0
  • ConstantIfExpression(条件恒true like:if(true))
  • DeadCode (永远不会执行的代码 like:if(a = 1) return 1; return 2;//deadcode)
  • DoubleNegative(双重否定 like:if(!!a))
  • ForLoopShouldBeWhileLoop (在应该使用while的时候是用来for)
  • GotoStatement (使用goto 语句 like:goto a
  • JumbledIncrementer 乱七八糟的增量 like:
for (int i = 0; i < a; i++) {
        for (int j = 0; j < a; i++) { // references both 'i' and 'j'
        }
    }
  • MisplacedNilCheck (nil 检查被放错了地方、在OC中、向一个nil对象发送消息、什么也不会发生、但是代码读起来会很让人费解 like:if ([obj1 isEqualTo:obj2] && obj1))
  • MisplacedNullCheck (null check被放错了地方、在C 和C++中、想一个null 指针发送消息会导致crash like:if (a->bar(b) && a != NULL)
  • MultipleUnaryOperator (多重一元操作很难理解 like:int b = -(+(!(~1)));)
  • ReturnFromFinallyBlock(在finallyBlock 中return 是不推荐的)
@try
    {
        foo();
    }
    @catch(id ex)
    {
        bar();
    }
    @finally
    {
        return;         // this can discard exceptions.
    }
  • ThrowExceptionFromFinallyBlock()
@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(objc)

  • ObjCVerifyIsEqualHash(重写isEqual 一定要重写 hash)
  • ObjCVerifyIsEqualHash(必须call super的情况 比如 layoutSubViews
  • ObjCVerifyProtectedMethod(因为在OC中是没有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
  • ObjCVerifySubclassMustImplement (子类必须实现的方法)
@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

Convention(惯例)

  • AvoidBranchingStatementAsLastInLoop (在一个循环的最后语句中使用break非常让人疑惑)
    for (int i = 0; i < 10; i++)
    {
        if (foo(i))
        {
            continue;
        }
        break;      // this break is confusing
    }
  • CoveredSwitchStatementsDontNeedDefault (switch中如果case覆盖了所有的情况、那么defaul 是不需要的)
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.
    }
}
  • DefaultLabelNotLastInSwitchStatement(default没有在最后一个)
void example(int a)
{
    switch (a) {
        case 1:
            break;
        default:  // the default case should be last
            break;
        case 2:
            break;
    }
}
  • DestructorOfVirtualClass(虚类的子数的解析函数也要是虚函数)
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(反转逻辑很难理解)
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 (switch中缺少break)
  • NonCaseLabelInSwitchStatement (switch中缺少case)
  • ObjCAssignIvarOutsideAccessors (禁止在setter、getter、和init之外定义变量)
@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(参数再赋值在大部分情况下是有问题的 like:if (a < 0){a = 0; // reassign parameter a to 0}
  • PreferEarlyExit (不期望的结果先判断)
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 ....
}
  • SwitchStatementsShouldHaveDefault
  • TooFewBranchesInSwitchStatement(如果swtich的case很少、建议使用if)

Empty(空)

  • EmpthCatchStatement (一个exception 被catch、但是什么也没做)
    try
    {
        int* m= new int[1000];
    }
    catch(...)                  // empty catch statement, this swallows an exception
    {
    }
  • EmptyDoWhileStatement
do
    {                           // empty do-while statement
    } while(1);
  • EmptyElseBlock
  if (1)
    {
        return a + 1;
    }
    else                // empty else statement, can be safely removed
    {
    }
  • EmptyFinallyStatement
 Foo *foo;
    @try
    {
        [foo bar];
    }
    @catch(NSException *e)
    {
        NSLog(@"Exception occurred: %@", [e description]);
    }
    @finally            // empty finally statement, probably forget to clean up?
    {
    }
  • EmptyForStatement
    for (;;)                // empty for statement
    {
    }

    for (id it in array)    // empty for-each statement
    {
    }
  • EmptyIfStatement
    if (a == 1)                  // empty if statement
    {
    }
  • EmptySwitchStatement
    switch (i)              // empty switch statement
    {
    }
  • EmptyTryStatement
  • EmptyWhileStatement

Migration(移植、感觉叫最佳实践更好理解)

  • ObjCBoxedExpressions(可以使用简单的写法、 就尽量不要太繁琐)
void aMethod()
{
    NSNumber *fortyTwo = [NSNumber numberWithInt:(43 - 1)];
    // NSNumber *fortyTwo = @(43 - 1);

    NSString *env = [NSString stringWithUTF8String:getenv("PATH")];
    // NSString *env = @(getenv("PATH"));
}
  • ObjCContainerLiterals
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 };
}
  • ObjCNSNumberLiterals
void aMethod()
{
    NSNumber *fortyTwo = [NSNumber numberWithInt:42];
    // NSNumber *fortyTwo = @42;

    NSNumber *yesBool = [NSNumber numberWithBool:YES];
    // NSNumber *yesBool = @YES;
}
  • ObjCObjectSubscripting
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 (太长的变量名称)
  • LongVariableName (过短的变量名称)

Redundant(多余的)

  • RedundantConditionalOperator
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
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
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
+ (void)compare:(A *)obj1 withOther:(A *)obj2
{
    if (obj1 && [obj1 isEqualTo:obj2]) // if ([obj1 isEqualTo:obj2]) is okay
    {
    }
}
  • UnnecessaryElseStatement
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."
    }                           //
}
  • UnnecessaryNullCheckForCXXDealloc
void m(char* c) {
    if (c != nullptr) { // and be simplified to delete c;
        delete c;
    }
  • UselessParentheses
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(尺寸)

  • CyclomaticComplexity(圈复杂度)
  • LongClass(过大的类)
  • LongLine (每行过长)
  • LongMethod (方法过长)
  • NcssMethodCount(Ncss:Non Commenting Source Statements 没有说明的代码的数量 方法数量)
  • NestedBlockDepth (层次过大)
  • NPathComplexity (NPath 复杂度)
  • TooManyFields (太多的域)
class c
{
    int a, b;
    int c;
    // ...
    int l;
    int m, n;
    // ...
    int x, y, z;

    void m() {}
};
  • TooManyMethods
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();
};
  • TooManyParameters
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)
{
}

Unused(从未被使用)

  • UnusedLocalVariable (未被使用的本地变量)
  • UnusedMethodParameter (未被使用的方法)

注:这些规则你可以在http://docs.oclint.org/en/stable/rules/index.html?highlight=rules找到

之后的博客会更新如何自定义检查规则,敬请期待。

 类似资料: