diff --git a/infer/src/clang/cFrontend_checkers.ml b/infer/src/clang/cFrontend_checkers.ml index 5d35088ea..152e20487 100644 --- a/infer/src/clang/cFrontend_checkers.ml +++ b/infer/src/clang/cFrontend_checkers.ml @@ -277,23 +277,20 @@ let captured_cxx_ref_in_objc_block_warning _ stmt_info captured_vars = let bad_pointer_comparison_warning _ stmt_info stmts = let rec condition stmts = let condition_aux stmt = - match stmt with - | Clang_ast_t.CallExpr _ - | Clang_ast_t.CXXMemberCallExpr _ - | Clang_ast_t.CXXOperatorCallExpr _ - | Clang_ast_t.ObjCMessageExpr _ -> false - | Clang_ast_t.BinaryOperator (_, _, _, boi) - when (boi.boi_kind = `NE) || (boi.boi_kind = `EQ) -> false - | Clang_ast_t.UnaryOperator (_, stmts, _, uoi) when uoi.uoi_kind = `LNot -> + match (stmt: Clang_ast_t.stmt) with + | BinaryOperator (_, _, _, boi) when + (boi.boi_kind = `EQ) || (boi.boi_kind = `NE) -> false + | BinaryOperator (_, stmts, _, _) -> condition stmts + | UnaryOperator (_, stmts, _, uoi) when uoi.uoi_kind = `LNot -> + condition stmts + | ImplicitCastExpr (_, stmts, _, _) + | ExprWithCleanups (_, stmts, _, _) -> condition stmts | stmt -> match Clang_ast_proj.get_expr_tuple stmt with - | Some (_, stmts, expr_info) -> + | Some (_, _, expr_info) -> let typ = CFrontend_utils.Ast_utils.get_desugared_type expr_info.ei_type_ptr in - if CFrontend_utils.Ast_utils.is_ptr_to_objc_class typ "NSNumber" then - true - else - condition stmts + CFrontend_utils.Ast_utils.is_ptr_to_objc_class typ "NSNumber" | _ -> false in IList.exists condition_aux stmts in if condition stmts then diff --git a/infer/tests/codetoanalyze/objc/linters/badpointer.m b/infer/tests/codetoanalyze/objc/linters/badpointer.m index 42c34b488..868bc01dc 100644 --- a/infer/tests/codetoanalyze/objc/linters/badpointer.m +++ b/infer/tests/codetoanalyze/objc/linters/badpointer.m @@ -53,3 +53,93 @@ void good2() { i = 0; } } + +int good3(NSNumber* number) { + if (number.doubleValue) { + return 0; + } + return 1; +} + +//--- + +@interface Simple : NSObject + +@property(strong, atomic) NSNumber* number; + +- (NSNumber*)fooWithCondition:(BOOL)number andNumber:(NSNumber*)number; + +@end + +@implementation Simple + +- (NSNumber*)fooWithCondition:(BOOL)condition andNumber:(NSNumber*)number { + return number; +} + +@end + +//--- + +int bad4(NSNumber* number, Simple* simple) { + if ([simple fooWithCondition:true andNumber:number] < 19) { + return 0; + } + return 1; +} + +int good4(NSNumber* number, Simple* simple) { + if ([simple fooWithCondition:true andNumber:number].doubleValue) { + return 0; + } + return 1; +} + +int bad5(NSNumber* number, Simple* simple) { + if ([simple fooWithCondition:(number ? 1 : 2) andNumber:number] != nil) { + return 0; + } + return 1; +} + +int bad6(NSNumber* number, Simple* simple) { + if ([simple fooWithCondition:(number == nil ? 1 : 2) andNumber:number]) { + return 0; + } + return 1; +} + +int good5(NSNumber* number, Simple* simple) { + if ([simple fooWithCondition:(number == nil ? 1 : 2) andNumber:number] != + nil) { + return 0; + } + return 1; +} + +int bad7(NSNumber* number) { + if (number < 0) { + return 0; + } + return 1; +} + +int bad8(NSNumber* number) { + if (number) { + return 0; + } + return 1; +} + +int bad9(NSNumber* number, Simple* simple) { + simple.number = simple.number ? simple.number : number; +} + +int bad10(NSNumber* number, Simple* simple) { + if ([simple fooWithCondition:true andNumber:number]) { + return 1; + } + return 0; +} + +int good6(NSNumber* number) { return (number.integerValue > 5 ? 1 : 0); } diff --git a/infer/tests/endtoend/objc/linters/NSNumber2Test.java b/infer/tests/endtoend/objc/linters/NSNumber2Test.java index 9c2229b29..274c559b7 100644 --- a/infer/tests/endtoend/objc/linters/NSNumber2Test.java +++ b/infer/tests/endtoend/objc/linters/NSNumber2Test.java @@ -51,7 +51,7 @@ public class NSNumber2Test { assertThat( "Results should contain " + BAD_POINTER_COMPARISON, inferResults, - containsOnlyLines(new int[]{17, 26, 33})); + containsOnlyLines(new int[]{17, 26, 33, 85, 99, 106, 121, 128, 135, 139})); } }