diff --git a/infer/src/al/AL.ml b/infer/src/al/AL.ml index cd5ac3d8d..ba94d70b4 100644 --- a/infer/src/al/AL.ml +++ b/infer/src/al/AL.ml @@ -208,24 +208,6 @@ let compute_if_context (context : CLintersContext.context) stmt = : CLintersContext.if_context ) -let get_method_body_opt decl = - let open Clang_ast_t in - match decl with - | FunctionDecl (_, _, _, fdi) - | CXXMethodDecl (_, _, _, fdi, _) - | CXXConstructorDecl (_, _, _, fdi, _) - | CXXConversionDecl (_, _, _, fdi, _) - | CXXDestructorDecl (_, _, _, fdi, _) -> - fdi.Clang_ast_t.fdi_body - | ObjCMethodDecl (_, _, mdi) -> - mdi.Clang_ast_t.omdi_body - | BlockDecl (_, block_decl_info) -> - block_decl_info.Clang_ast_t.bdi_body - | _ -> - Logging.die InternalError "Should only be called with method, but got %s" - (Clang_ast_proj.get_decl_kind_string decl) - - let call_tableaux linters cxt an map_active = if CFrontend_config.tableaux_evaluation then Tableaux.build_valuation linters an cxt map_active @@ -332,7 +314,7 @@ and do_frontend_checks_decl linters (context : CLintersContext.context) (* We need to visit explicitly nodes reachable via Parameters transitions because they won't be visited during the evaluation of the formula *) do_frontend_checks_via_transition linters context' map_active an CTL.Parameters ; - ( match get_method_body_opt decl with + ( match CAst_utils.get_method_body_opt decl with | Some stmt -> do_frontend_checks_stmt linters context' map_active stmt | None -> diff --git a/infer/src/clang/astToRangeMap.ml b/infer/src/clang/astToRangeMap.ml index 54f07736f..63b29ebad 100644 --- a/infer/src/clang/astToRangeMap.ml +++ b/infer/src/clang/astToRangeMap.ml @@ -36,28 +36,49 @@ let clang_proc_of_decl decl = None -let process_ast ast default_source_file = +let rec process_block_decls_in_stmts default_source_file ast_range stmts = let open Clang_ast_t in - let rec extract_location ast_range decl = - match decl with - | ObjCMethodDecl (di, _, _) - | CXXConversionDecl (di, _, _, _, _) - | FunctionDecl (di, _, _, _) - | CXXMethodDecl (di, _, _, _, _) - | CXXConstructorDecl (di, _, _, _, _) - | CXXDestructorDecl (di, _, _, _, _) - | BlockDecl (di, _) -> - let range = CLocation.location_of_decl_info default_source_file di in - let procname = CType_decl.CProcname.from_decl decl in - let clang_proc = clang_proc_of_decl decl in - Typ.Procname.Map.add procname (range, clang_proc) ast_range - | _ -> ( - match Clang_ast_proj.get_decl_context_tuple decl with - | Some (decls, _) -> - List.fold decls ~f:extract_location ~init:ast_range - | None -> - ast_range ) + let process_decls_in_stmt ast_range stmt = + let _, stmts = Clang_ast_proj.get_stmt_tuple stmt in + let ast_range' = process_block_decls_in_stmts default_source_file ast_range stmts in + match stmt with + | BlockExpr (_, _, _, decl) -> + process_proc_decl default_source_file ast_range' decl + | _ -> + ast_range' in + List.fold ~f:process_decls_in_stmt ~init:ast_range stmts + + +and process_proc_decl default_source_file ast_range decl = + let open Clang_ast_t in + match decl with + | ObjCMethodDecl (di, _, _) + | CXXConversionDecl (di, _, _, _, _) + | FunctionDecl (di, _, _, _) + | CXXMethodDecl (di, _, _, _, _) + | CXXConstructorDecl (di, _, _, _, _) + | CXXDestructorDecl (di, _, _, _, _) + | BlockDecl (di, _) -> ( + let range = CLocation.location_of_decl_info default_source_file di in + let procname = CType_decl.CProcname.from_decl decl in + let clang_proc = clang_proc_of_decl decl in + let ast_range' = Typ.Procname.Map.add procname (range, clang_proc) ast_range in + match CAst_utils.get_method_body_opt decl with + | Some stmt -> + process_block_decls_in_stmts default_source_file ast_range' [stmt] + | None -> + ast_range' ) + | _ -> ( + match Clang_ast_proj.get_decl_context_tuple decl with + | Some (decls, _) -> + List.fold ~f:(process_proc_decl default_source_file) ~init:ast_range decls + | None -> + ast_range ) + + +let process_ast ast default_source_file = + let open Clang_ast_t in match ast with | TranslationUnitDecl (_, decl_list, _, _) -> List.fold decl_list ~init:Typ.Procname.Map.empty ~f:(fun map decl -> @@ -66,7 +87,7 @@ let process_ast ast default_source_file = if CLocation.should_translate_lib default_source_file source_range `DeclTraversal ~translate_when_used:true - then extract_location map decl + then process_proc_decl default_source_file map decl else map ) | _ -> assert false diff --git a/infer/src/clang/cAst_utils.ml b/infer/src/clang/cAst_utils.ml index da53d80b6..cbd6ea155 100644 --- a/infer/src/clang/cAst_utils.ml +++ b/infer/src/clang/cAst_utils.ml @@ -588,3 +588,21 @@ let get_superclass_curr_class_objc_from_decl (decl : Clang_ast_t.decl) = "Expected to be called only with ObjCInterfaceDecl, ObjCImplementationDecl, \ ObjCCategoryDecl or ObjCCategoryImplDecl, but got %s" (Clang_ast_proj.get_decl_kind_string decl) + + +let get_method_body_opt decl = + let open Clang_ast_t in + match decl with + | FunctionDecl (_, _, _, fdi) + | CXXMethodDecl (_, _, _, fdi, _) + | CXXConstructorDecl (_, _, _, fdi, _) + | CXXConversionDecl (_, _, _, fdi, _) + | CXXDestructorDecl (_, _, _, fdi, _) -> + fdi.Clang_ast_t.fdi_body + | ObjCMethodDecl (_, _, mdi) -> + mdi.Clang_ast_t.omdi_body + | BlockDecl (_, block_decl_info) -> + block_decl_info.Clang_ast_t.bdi_body + | _ -> + Logging.die InternalError "Should only be called with method, but got %s" + (Clang_ast_proj.get_decl_kind_string decl) diff --git a/infer/src/clang/cAst_utils.mli b/infer/src/clang/cAst_utils.mli index 27aee1e63..50d126468 100644 --- a/infer/src/clang/cAst_utils.mli +++ b/infer/src/clang/cAst_utils.mli @@ -147,3 +147,5 @@ val has_block_attribute : Clang_ast_t.decl -> bool val is_implicit_decl : Clang_ast_t.decl -> bool val get_superclass_curr_class_objc_from_decl : Clang_ast_t.decl -> Clang_ast_t.decl_ref option + +val get_method_body_opt : Clang_ast_t.decl -> Clang_ast_t.stmt option diff --git a/infer/src/test_determinator/testDeterminator.ml b/infer/src/test_determinator/testDeterminator.ml index b5e19b095..004b7ff9b 100644 --- a/infer/src/test_determinator/testDeterminator.ml +++ b/infer/src/test_determinator/testDeterminator.ml @@ -208,6 +208,13 @@ let match_profiler_samples_affected_methods native_symbols affected_methods = String.equal name native_symbol.Clang_profiler_samples_t.name | Some (ClangProc.ObjcMethod {mangled_name}) -> String.equal mangled_name native_symbol.Clang_profiler_samples_t.name + | Some (ClangProc.ObjcBlock {mangled_name}) -> ( + match native_symbol.Clang_profiler_samples_t.mangled_name with + | Some native_sym_mangled_name -> + (* Assuming mangled name is there for blocks *) + String.equal native_sym_mangled_name mangled_name + | None -> + false ) | _ -> false (* TODO: deal with mangled names, other method kinds *) diff --git a/infer/tests/build_systems/clang_test_determinator/mod1-A.mm b/infer/tests/build_systems/clang_test_determinator/mod1-A.mm index 3e026d875..85d96af8a 100644 --- a/infer/tests/build_systems/clang_test_determinator/mod1-A.mm +++ b/infer/tests/build_systems/clang_test_determinator/mod1-A.mm @@ -55,4 +55,26 @@ void Cube::sort(Cube* xs, unsigned n) { NSLog(@"The person's name is %@", _name); } ++ (void)multiply { + double (^multiplyTwoValues)(double, double) = + ^(double first, double second) { // change here + return first * second; + }; + + double result = multiplyTwoValues(2, 4); + + NSLog(@"The result is %f", result); +} + @end + +void sum() { + double (^sumTwoValues)(double, double) = + ^(double firstValue, double secondValue) { + return firstValue + secondValue; + }; + + double result = sumTwoValues(2, 4); + + NSLog(@"The result is %f", result); +} diff --git a/infer/tests/build_systems/clang_test_determinator/mod2-A.mm b/infer/tests/build_systems/clang_test_determinator/mod2-A.mm index 1782cccee..24b61b529 100644 --- a/infer/tests/build_systems/clang_test_determinator/mod2-A.mm +++ b/infer/tests/build_systems/clang_test_determinator/mod2-A.mm @@ -56,4 +56,26 @@ void Cube::sort(Cube* xs, unsigned n) { NSLog(@"The name is %@", _name); // change here } ++ (void)multiply { + double (^multiplyTwoValues)(double, double) = + ^(double firstValue, double secondValue) { + return firstValue * secondValue; + }; + + double result = multiplyTwoValues(2, 4); + + NSLog(@"The result is %f", result); +} + @end + +void sum() { + double (^sumTwoValues)(double, double) = + ^(double first, double second) { // change here + return first + second; + }; + + double result = sumTwoValues(2, 4); + + NSLog(@"The result is %f", result); +} diff --git a/infer/tests/build_systems/clang_test_determinator/orig-A.mm b/infer/tests/build_systems/clang_test_determinator/orig-A.mm index 5cfd7899d..f5560644e 100644 --- a/infer/tests/build_systems/clang_test_determinator/orig-A.mm +++ b/infer/tests/build_systems/clang_test_determinator/orig-A.mm @@ -55,4 +55,26 @@ void Cube::sort(Cube* xs, unsigned n) { NSLog(@"The person's name is %@", _name); } ++ (void)multiply { + double (^multiplyTwoValues)(double, double) = + ^(double firstValue, double secondValue) { + return firstValue * secondValue; + }; + + double result = multiplyTwoValues(2, 4); + + NSLog(@"The result is %f", result); +} + @end + +void sum() { + double (^sumTwoValues)(double, double) = + ^(double firstValue, double secondValue) { + return firstValue + secondValue; + }; + + double result = sumTwoValues(2, 4); + + NSLog(@"The result is %f", result); +} diff --git a/infer/tests/build_systems/clang_test_determinator/profiler_samples.json b/infer/tests/build_systems/clang_test_determinator/profiler_samples.json index 2137e4126..3b74f2d4d 100644 --- a/infer/tests/build_systems/clang_test_determinator/profiler_samples.json +++ b/infer/tests/build_systems/clang_test_determinator/profiler_samples.json @@ -65,5 +65,41 @@ ], "field5": {}, "field6": {} + }, + { + "field1": {}, + "field2": {}, + "field3": {}, + "test": "label1_block", + "field4": {}, + "native_symbols": [ + { + "name": "", + "mangled_name": "__18+[Person multiply]_block_invoke" + }, + { + "name": "exampleMethod3" + } + ], + "field5": {}, + "field6": {} + }, + { + "field1": {}, + "field2": {}, + "field3": {}, + "test": "label2_block", + "field4": {}, + "native_symbols": [ + { + "name": "", + "mangled_name": "___Z3sumv_block_invoke_2" + }, + { + "name": "exampleMethod3" + } + ], + "field5": {}, + "field6": {} } ] diff --git a/infer/tests/build_systems/clang_test_determinator/test_determinator.json.mod1.exp b/infer/tests/build_systems/clang_test_determinator/test_determinator.json.mod1.exp index 2987c0c74..aecc7e34e 100644 --- a/infer/tests/build_systems/clang_test_determinator/test_determinator.json.mod1.exp +++ b/infer/tests/build_systems/clang_test_determinator/test_determinator.json.mod1.exp @@ -1 +1 @@ -["label1_objc_method","label1_c_function"] \ No newline at end of file +["label1_block","label1_objc_method","label1_c_function"] \ No newline at end of file diff --git a/infer/tests/build_systems/clang_test_determinator/test_determinator.json.mod2.exp b/infer/tests/build_systems/clang_test_determinator/test_determinator.json.mod2.exp index 7869ab3b6..5ea829613 100644 --- a/infer/tests/build_systems/clang_test_determinator/test_determinator.json.mod2.exp +++ b/infer/tests/build_systems/clang_test_determinator/test_determinator.json.mod2.exp @@ -1 +1 @@ -["label2_objc_method","label2_c_function"] \ No newline at end of file +["label2_block","label2_objc_method","label2_c_function"] \ No newline at end of file