|  |  |  | @ -90,67 +90,75 @@ and contains_ck_impl decl_list = | 
			
		
	
		
			
				
					|  |  |  |  |     const NSString *y; | 
			
		
	
		
			
				
					|  |  |  |  |     ``` *) | 
			
		
	
		
			
				
					|  |  |  |  | let mutable_local_vars_advice context an = | 
			
		
	
		
			
				
					|  |  |  |  |   let rec get_referenced_type (qual_type: Clang_ast_t.qual_type) : Clang_ast_t.decl option = | 
			
		
	
		
			
				
					|  |  |  |  |     let typ_opt = CAst_utils.get_desugared_type qual_type.qt_type_ptr in | 
			
		
	
		
			
				
					|  |  |  |  |     match (typ_opt : Clang_ast_t.c_type option) with | 
			
		
	
		
			
				
					|  |  |  |  |     | Some ObjCInterfaceType (_, decl_ptr) | Some RecordType (_, decl_ptr) -> | 
			
		
	
		
			
				
					|  |  |  |  |         CAst_utils.get_decl decl_ptr | 
			
		
	
		
			
				
					|  |  |  |  |     | Some PointerType (_, inner_qual_type) | 
			
		
	
		
			
				
					|  |  |  |  |     | Some ObjCObjectPointerType (_, inner_qual_type) | 
			
		
	
		
			
				
					|  |  |  |  |     | Some LValueReferenceType (_, inner_qual_type) -> | 
			
		
	
		
			
				
					|  |  |  |  |         get_referenced_type inner_qual_type | 
			
		
	
		
			
				
					|  |  |  |  |     | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |         None | 
			
		
	
		
			
				
					|  |  |  |  |   in | 
			
		
	
		
			
				
					|  |  |  |  |   let is_of_whitelisted_type qual_type = | 
			
		
	
		
			
				
					|  |  |  |  |     let cpp_whitelist = | 
			
		
	
		
			
				
					|  |  |  |  |       [ "CKComponentScope" | 
			
		
	
		
			
				
					|  |  |  |  |       ; "FBTrackingNodeScope" | 
			
		
	
		
			
				
					|  |  |  |  |       ; "FBTrackingCodeScope" | 
			
		
	
		
			
				
					|  |  |  |  |       ; "CKComponentContext" | 
			
		
	
		
			
				
					|  |  |  |  |       ; "CKComponentKey" ] | 
			
		
	
		
			
				
					|  |  |  |  |   try | 
			
		
	
		
			
				
					|  |  |  |  |     let rec get_referenced_type (qual_type: Clang_ast_t.qual_type) : Clang_ast_t.decl option = | 
			
		
	
		
			
				
					|  |  |  |  |       let typ_opt = CAst_utils.get_desugared_type qual_type.qt_type_ptr in | 
			
		
	
		
			
				
					|  |  |  |  |       match (typ_opt : Clang_ast_t.c_type option) with | 
			
		
	
		
			
				
					|  |  |  |  |       | Some ObjCInterfaceType (_, decl_ptr) | Some RecordType (_, decl_ptr) -> | 
			
		
	
		
			
				
					|  |  |  |  |           CAst_utils.get_decl decl_ptr | 
			
		
	
		
			
				
					|  |  |  |  |       | Some PointerType (_, inner_qual_type) | 
			
		
	
		
			
				
					|  |  |  |  |       | Some ObjCObjectPointerType (_, inner_qual_type) | 
			
		
	
		
			
				
					|  |  |  |  |       | Some LValueReferenceType (_, inner_qual_type) -> | 
			
		
	
		
			
				
					|  |  |  |  |           get_referenced_type inner_qual_type | 
			
		
	
		
			
				
					|  |  |  |  |       | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |           None | 
			
		
	
		
			
				
					|  |  |  |  |     in | 
			
		
	
		
			
				
					|  |  |  |  |     let objc_whitelist = ["NSError"] in | 
			
		
	
		
			
				
					|  |  |  |  |     match get_referenced_type qual_type with | 
			
		
	
		
			
				
					|  |  |  |  |     | Some CXXRecordDecl (_, ndi, _, _, _, _, _, _) -> | 
			
		
	
		
			
				
					|  |  |  |  |         List.mem ~equal:String.equal cpp_whitelist ndi.ni_name | 
			
		
	
		
			
				
					|  |  |  |  |     | Some ObjCInterfaceDecl (_, ndi, _, _, _) -> | 
			
		
	
		
			
				
					|  |  |  |  |         List.mem ~equal:String.equal objc_whitelist ndi.ni_name | 
			
		
	
		
			
				
					|  |  |  |  |     | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |         false | 
			
		
	
		
			
				
					|  |  |  |  |   in | 
			
		
	
		
			
				
					|  |  |  |  |   match an with | 
			
		
	
		
			
				
					|  |  |  |  |   | Ctl_parser_types.Decl (Clang_ast_t.VarDecl (decl_info, named_decl_info, qual_type, _) as decl) -> | 
			
		
	
		
			
				
					|  |  |  |  |       let is_const_ref = | 
			
		
	
		
			
				
					|  |  |  |  |         match CAst_utils.get_type qual_type.qt_type_ptr with | 
			
		
	
		
			
				
					|  |  |  |  |         | Some LValueReferenceType (_, {Clang_ast_t.qt_is_const}) -> | 
			
		
	
		
			
				
					|  |  |  |  |             qt_is_const | 
			
		
	
		
			
				
					|  |  |  |  |         | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |             false | 
			
		
	
		
			
				
					|  |  |  |  |       in | 
			
		
	
		
			
				
					|  |  |  |  |       let is_const = qual_type.qt_is_const || is_const_ref in | 
			
		
	
		
			
				
					|  |  |  |  |       let condition = | 
			
		
	
		
			
				
					|  |  |  |  |         is_ck_context context an && not (CAst_utils.is_syntactically_global_var decl) | 
			
		
	
		
			
				
					|  |  |  |  |         && not (CAst_utils.is_static_local_var decl) && not is_const | 
			
		
	
		
			
				
					|  |  |  |  |         && not (is_of_whitelisted_type qual_type) && not decl_info.di_is_implicit | 
			
		
	
		
			
				
					|  |  |  |  |         && not context.CLintersContext.in_for_loop_declaration | 
			
		
	
		
			
				
					|  |  |  |  |         && not (CAst_utils.is_std_vector qual_type) && not (CAst_utils.has_block_attribute decl) | 
			
		
	
		
			
				
					|  |  |  |  |     let is_of_whitelisted_type qual_type = | 
			
		
	
		
			
				
					|  |  |  |  |       let cpp_whitelist = | 
			
		
	
		
			
				
					|  |  |  |  |         [ "CKComponentScope" | 
			
		
	
		
			
				
					|  |  |  |  |         ; "FBTrackingNodeScope" | 
			
		
	
		
			
				
					|  |  |  |  |         ; "FBTrackingCodeScope" | 
			
		
	
		
			
				
					|  |  |  |  |         ; "CKComponentContext" | 
			
		
	
		
			
				
					|  |  |  |  |         ; "CKComponentKey" ] | 
			
		
	
		
			
				
					|  |  |  |  |       in | 
			
		
	
		
			
				
					|  |  |  |  |       if condition then | 
			
		
	
		
			
				
					|  |  |  |  |         Some | 
			
		
	
		
			
				
					|  |  |  |  |           { CIssue.id= "MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE" | 
			
		
	
		
			
				
					|  |  |  |  |           ; name= None | 
			
		
	
		
			
				
					|  |  |  |  |           ; severity= Exceptions.Kadvice | 
			
		
	
		
			
				
					|  |  |  |  |           ; mode= CIssue.On | 
			
		
	
		
			
				
					|  |  |  |  |           ; description= | 
			
		
	
		
			
				
					|  |  |  |  |               "Local variable " ^ MF.monospaced_to_string named_decl_info.ni_name | 
			
		
	
		
			
				
					|  |  |  |  |               ^ " should be const to avoid reassignment" | 
			
		
	
		
			
				
					|  |  |  |  |           ; suggestion= Some "Add a const (after the asterisk for pointer types)." | 
			
		
	
		
			
				
					|  |  |  |  |           ; doc_url= None | 
			
		
	
		
			
				
					|  |  |  |  |           ; loc= CFrontend_checkers.location_from_dinfo context decl_info } | 
			
		
	
		
			
				
					|  |  |  |  |       else None | 
			
		
	
		
			
				
					|  |  |  |  |   | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |       None | 
			
		
	
		
			
				
					|  |  |  |  |       let objc_whitelist = ["NSError"] in | 
			
		
	
		
			
				
					|  |  |  |  |       match get_referenced_type qual_type with | 
			
		
	
		
			
				
					|  |  |  |  |       | Some CXXRecordDecl (_, ndi, _, _, _, _, _, _) -> | 
			
		
	
		
			
				
					|  |  |  |  |           List.mem ~equal:String.equal cpp_whitelist ndi.ni_name | 
			
		
	
		
			
				
					|  |  |  |  |       | Some ObjCInterfaceDecl (_, ndi, _, _, _) -> | 
			
		
	
		
			
				
					|  |  |  |  |           List.mem ~equal:String.equal objc_whitelist ndi.ni_name | 
			
		
	
		
			
				
					|  |  |  |  |       | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |           false | 
			
		
	
		
			
				
					|  |  |  |  |     in | 
			
		
	
		
			
				
					|  |  |  |  |     if is_ck_context context an then | 
			
		
	
		
			
				
					|  |  |  |  |       match an with | 
			
		
	
		
			
				
					|  |  |  |  |       | Ctl_parser_types.Decl | 
			
		
	
		
			
				
					|  |  |  |  |           (Clang_ast_t.VarDecl (decl_info, named_decl_info, qual_type, _) as decl) -> | 
			
		
	
		
			
				
					|  |  |  |  |           let is_const_ref = | 
			
		
	
		
			
				
					|  |  |  |  |             match CAst_utils.get_type qual_type.qt_type_ptr with | 
			
		
	
		
			
				
					|  |  |  |  |             | Some LValueReferenceType (_, {Clang_ast_t.qt_is_const}) -> | 
			
		
	
		
			
				
					|  |  |  |  |                 qt_is_const | 
			
		
	
		
			
				
					|  |  |  |  |             | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |                 false | 
			
		
	
		
			
				
					|  |  |  |  |           in | 
			
		
	
		
			
				
					|  |  |  |  |           let is_const = qual_type.qt_is_const || is_const_ref in | 
			
		
	
		
			
				
					|  |  |  |  |           let should_not_report_mutable_local = | 
			
		
	
		
			
				
					|  |  |  |  |             CAst_utils.is_syntactically_global_var decl || CAst_utils.is_static_local_var decl | 
			
		
	
		
			
				
					|  |  |  |  |             || is_const || is_of_whitelisted_type qual_type || decl_info.di_is_implicit | 
			
		
	
		
			
				
					|  |  |  |  |             || context.CLintersContext.in_for_loop_declaration | 
			
		
	
		
			
				
					|  |  |  |  |             || CAst_utils.is_std_vector qual_type || CAst_utils.has_block_attribute decl | 
			
		
	
		
			
				
					|  |  |  |  |           in | 
			
		
	
		
			
				
					|  |  |  |  |           if should_not_report_mutable_local then None | 
			
		
	
		
			
				
					|  |  |  |  |           else | 
			
		
	
		
			
				
					|  |  |  |  |             Some | 
			
		
	
		
			
				
					|  |  |  |  |               { CIssue.id= "MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE" | 
			
		
	
		
			
				
					|  |  |  |  |               ; name= None | 
			
		
	
		
			
				
					|  |  |  |  |               ; severity= Exceptions.Kadvice | 
			
		
	
		
			
				
					|  |  |  |  |               ; mode= CIssue.On | 
			
		
	
		
			
				
					|  |  |  |  |               ; description= | 
			
		
	
		
			
				
					|  |  |  |  |                   "Local variable " ^ MF.monospaced_to_string named_decl_info.ni_name | 
			
		
	
		
			
				
					|  |  |  |  |                   ^ " should be const to avoid reassignment" | 
			
		
	
		
			
				
					|  |  |  |  |               ; suggestion= Some "Add a const (after the asterisk for pointer types)." | 
			
		
	
		
			
				
					|  |  |  |  |               ; doc_url= None | 
			
		
	
		
			
				
					|  |  |  |  |               ; loc= CFrontend_checkers.location_from_dinfo context decl_info } | 
			
		
	
		
			
				
					|  |  |  |  |       | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |           None | 
			
		
	
		
			
				
					|  |  |  |  |     else None | 
			
		
	
		
			
				
					|  |  |  |  |   with CFrontend_config.IncorrectAssumption e -> | 
			
		
	
		
			
				
					|  |  |  |  |     let trans_unit_ctx = context.CLintersContext.translation_unit_context in | 
			
		
	
		
			
				
					|  |  |  |  |     ClangLogging.log_caught_exception trans_unit_ctx "IncorrectAssumption" e.position | 
			
		
	
		
			
				
					|  |  |  |  |       e.source_range e.ast_node ; | 
			
		
	
		
			
				
					|  |  |  |  |     None | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | (* Should only be called with a VarDecl *) | 
			
		
	
	
		
			
				
					|  |  |  | @ -163,26 +171,27 @@ let component_factory_function_advice context an = | 
			
		
	
		
			
				
					|  |  |  |  |   let is_component_if decl = | 
			
		
	
		
			
				
					|  |  |  |  |     CAst_utils.is_objc_if_descendant decl [CFrontend_config.ckcomponent_cl] | 
			
		
	
		
			
				
					|  |  |  |  |   in | 
			
		
	
		
			
				
					|  |  |  |  |   match an with | 
			
		
	
		
			
				
					|  |  |  |  |   | Ctl_parser_types.Decl | 
			
		
	
		
			
				
					|  |  |  |  |       Clang_ast_t.FunctionDecl (decl_info, _, (qual_type: Clang_ast_t.qual_type), _) -> | 
			
		
	
		
			
				
					|  |  |  |  |       let objc_interface = CAst_utils.qual_type_to_objc_interface qual_type in | 
			
		
	
		
			
				
					|  |  |  |  |       let condition = is_ck_context context an && is_component_if objc_interface in | 
			
		
	
		
			
				
					|  |  |  |  |       if condition then | 
			
		
	
		
			
				
					|  |  |  |  |         Some | 
			
		
	
		
			
				
					|  |  |  |  |           { CIssue.id= "COMPONENT_FACTORY_FUNCTION" | 
			
		
	
		
			
				
					|  |  |  |  |           ; name= None | 
			
		
	
		
			
				
					|  |  |  |  |           ; severity= Exceptions.Kadvice | 
			
		
	
		
			
				
					|  |  |  |  |           ; mode= CIssue.Off | 
			
		
	
		
			
				
					|  |  |  |  |           ; description= "Break out composite components" | 
			
		
	
		
			
				
					|  |  |  |  |           ; suggestion= | 
			
		
	
		
			
				
					|  |  |  |  |               Some | 
			
		
	
		
			
				
					|  |  |  |  |                 "Prefer subclassing CKCompositeComponent to static helper functions that return a CKComponent subclass." | 
			
		
	
		
			
				
					|  |  |  |  |           ; doc_url= None | 
			
		
	
		
			
				
					|  |  |  |  |           ; loc= CFrontend_checkers.location_from_dinfo context decl_info } | 
			
		
	
		
			
				
					|  |  |  |  |       else None | 
			
		
	
		
			
				
					|  |  |  |  |   | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |       None | 
			
		
	
		
			
				
					|  |  |  |  |   if is_ck_context context an then | 
			
		
	
		
			
				
					|  |  |  |  |     match an with | 
			
		
	
		
			
				
					|  |  |  |  |     | Ctl_parser_types.Decl | 
			
		
	
		
			
				
					|  |  |  |  |         Clang_ast_t.FunctionDecl (decl_info, _, (qual_type: Clang_ast_t.qual_type), _) -> | 
			
		
	
		
			
				
					|  |  |  |  |         let objc_interface = CAst_utils.qual_type_to_objc_interface qual_type in | 
			
		
	
		
			
				
					|  |  |  |  |         if is_component_if objc_interface then | 
			
		
	
		
			
				
					|  |  |  |  |           Some | 
			
		
	
		
			
				
					|  |  |  |  |             { CIssue.id= "COMPONENT_FACTORY_FUNCTION" | 
			
		
	
		
			
				
					|  |  |  |  |             ; name= None | 
			
		
	
		
			
				
					|  |  |  |  |             ; severity= Exceptions.Kadvice | 
			
		
	
		
			
				
					|  |  |  |  |             ; mode= CIssue.Off | 
			
		
	
		
			
				
					|  |  |  |  |             ; description= "Break out composite components" | 
			
		
	
		
			
				
					|  |  |  |  |             ; suggestion= | 
			
		
	
		
			
				
					|  |  |  |  |                 Some | 
			
		
	
		
			
				
					|  |  |  |  |                   "Prefer subclassing CKCompositeComponent to static helper functions that return a CKComponent subclass." | 
			
		
	
		
			
				
					|  |  |  |  |             ; doc_url= None | 
			
		
	
		
			
				
					|  |  |  |  |             ; loc= CFrontend_checkers.location_from_dinfo context decl_info } | 
			
		
	
		
			
				
					|  |  |  |  |         else None | 
			
		
	
		
			
				
					|  |  |  |  |     | _ -> | 
			
		
	
		
			
				
					|  |  |  |  |         None | 
			
		
	
		
			
				
					|  |  |  |  |   else None | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | (* Should only be called with FunctionDecl *) | 
			
		
	
	
		
			
				
					|  |  |  | 
 |