[clang] Add the types of captured variables to the procname of blocks

Reviewed By: mbouaziz

Differential Revision: D8735374

fbshipit-source-id: 5c7c0b2
master
Dulma Churchill 6 years ago committed by Facebook Github Bot
parent 5cff9c91f9
commit 5653839540

@ -1 +1 @@
Subproject commit 10eb1ac9bb9e94ae8332e84058f39699422a0e85 Subproject commit 4c1ba505123398d1bfb81fca198cafabffa84da9

@ -28,6 +28,21 @@ let get_method_kind meth_decl =
raise CFrontend_config.Invalid_declaration raise CFrontend_config.Invalid_declaration
let rec is_inside_objc_class_method meth_decl =
let open Clang_ast_t in
match meth_decl with
| ObjCMethodDecl _ ->
ProcAttributes.equal_clang_method_kind (get_method_kind meth_decl) ProcAttributes.OBJC_CLASS
| BlockDecl (di, _) -> (
match CAst_utils.get_decl_opt di.di_parent_pointer with
| Some decl ->
is_inside_objc_class_method decl
| None ->
false )
| _ ->
false
let get_return_type method_decl = let get_return_type method_decl =
let open Clang_ast_t in let open Clang_ast_t in
match method_decl with match method_decl with
@ -147,3 +162,12 @@ let is_variadic method_decl =
block_decl_info.bdi_is_variadic block_decl_info.bdi_is_variadic
| _ -> | _ ->
raise CFrontend_config.Invalid_declaration raise CFrontend_config.Invalid_declaration
let get_block_captured_variables method_decl =
let open Clang_ast_t in
match method_decl with
| BlockDecl (_, block_decl_info) ->
block_decl_info.bdi_captured_variables
| _ ->
[]

@ -11,6 +11,8 @@ open! IStd
val get_method_kind : Clang_ast_t.decl -> ProcAttributes.clang_method_kind val get_method_kind : Clang_ast_t.decl -> ProcAttributes.clang_method_kind
val is_inside_objc_class_method : Clang_ast_t.decl -> bool
val get_return_type : Clang_ast_t.decl -> Clang_ast_t.qual_type val get_return_type : Clang_ast_t.decl -> Clang_ast_t.qual_type
val get_param_decls : Clang_ast_t.decl -> Clang_ast_t.decl list val get_param_decls : Clang_ast_t.decl -> Clang_ast_t.decl list
@ -29,3 +31,5 @@ val get_pointer_to_property : Clang_ast_t.decl -> Clang_ast_t.pointer option
val is_objc_method : Clang_ast_t.decl -> bool val is_objc_method : Clang_ast_t.decl -> bool
val is_variadic : Clang_ast_t.decl -> bool val is_variadic : Clang_ast_t.decl -> bool
val get_block_captured_variables : Clang_ast_t.decl -> Clang_ast_t.block_captured_variable list

@ -110,6 +110,37 @@ module BuildMethodSignature = struct
params @ return_param params @ return_param
let type_of_captured_var qual_type_to_sil_type tenv ~is_block_inside_objc_class_method decl_ref =
match decl_ref with
| {Clang_ast_t.dr_name= Some {Clang_ast_t.ni_name}} ->
(* In Objective-C class methods, self is not the standard self instance, since in this
context we don't have an instance. Instead it is used to get the class of the method.
We translate this variables in a different way than normal, we don't treat them as
variables in Sil, instead we remove them and get the class directly in the frontend.
For that reason, we shouldn't add them as captured variables of blocks, since they
don't appear anywhere else in the translation. *)
if is_block_inside_objc_class_method && String.equal ni_name CFrontend_config.self then
None
else Some (Option.value_exn decl_ref.Clang_ast_t.dr_qual_type |> qual_type_to_sil_type tenv)
| _ ->
assert false
let types_of_captured_vars qual_type_to_sil_type tenv meth_decl =
let captured_vars = CMethodProperties.get_block_captured_variables meth_decl in
let is_block =
ProcAttributes.equal_clang_method_kind
(CMethodProperties.get_method_kind meth_decl)
ProcAttributes.BLOCK
in
let is_block_inside_objc_class_method =
is_block && CMethodProperties.is_inside_objc_class_method meth_decl
in
List.map ~f:(fun cv -> Option.value_exn cv.Clang_ast_t.bcv_variable) captured_vars
|> List.filter_map
~f:(type_of_captured_var qual_type_to_sil_type tenv ~is_block_inside_objc_class_method)
(** get return type of the function and optionally type of function's return parameter *) (** get return type of the function and optionally type of function's return parameter *)
let get_return_val_and_param_types qual_type_to_sil_type tenv ~block_return_type method_decl = let get_return_val_and_param_types qual_type_to_sil_type tenv ~block_return_type method_decl =
let return_qual_type = let return_qual_type =
@ -614,9 +645,13 @@ and procname_from_decl ?tenv ?block_return_type ?outer_proc meth_decl =
BuildMethodSignature.get_parameters qual_type_to_sil_type ~block_return_type tenv BuildMethodSignature.get_parameters qual_type_to_sil_type ~block_return_type tenv
meth_decl meth_decl
in in
List.map let parameter_types =
~f:(fun ({typ}: CMethodSignature.param_type) -> Typ.Procname.Parameter.of_typ typ) List.map ~f:(fun ({typ}: CMethodSignature.param_type) -> typ) parameters
parameters in
let captured_vars_types =
BuildMethodSignature.types_of_captured_vars qual_type_to_sil_type tenv meth_decl
in
List.map ~f:Typ.Procname.Parameter.of_typ (captured_vars_types @ parameter_types)
| None -> | None ->
[] []
in in
@ -707,6 +742,8 @@ let method_signature_of_decl = BuildMethodSignature.method_signature_of_decl qua
let should_add_return_param = BuildMethodSignature.should_add_return_param let should_add_return_param = BuildMethodSignature.should_add_return_param
let type_of_captured_var = BuildMethodSignature.type_of_captured_var qual_type_to_sil_type
module CProcname = struct module CProcname = struct
let from_decl = procname_from_decl let from_decl = procname_from_decl

@ -58,3 +58,6 @@ val method_signature_body_of_decl :
* [> `CXXConstructorInit of Clang_ast_t.cxx_ctor_initializer] list * [> `CXXConstructorInit of Clang_ast_t.cxx_ctor_initializer] list
val should_add_return_param : Typ.typ -> is_objc_method:bool -> bool val should_add_return_param : Typ.typ -> is_objc_method:bool -> bool
val type_of_captured_var :
Tenv.t -> is_block_inside_objc_class_method:bool -> Clang_ast_t.decl_ref -> Typ.typ option

@ -27,7 +27,6 @@ type t =
; tenv: Tenv.t ; tenv: Tenv.t
; cfg: Cfg.t ; cfg: Cfg.t
; procdesc: Procdesc.t ; procdesc: Procdesc.t
; is_immediate_objc_method: bool
; immediate_curr_class: curr_class ; immediate_curr_class: curr_class
; return_param_typ: Typ.t option ; return_param_typ: Typ.t option
; outer_context: t option ; outer_context: t option
@ -36,14 +35,13 @@ type t =
; vars_to_destroy: Clang_ast_t.decl list StmtMap.t } ; vars_to_destroy: Clang_ast_t.decl list StmtMap.t }
let create_context translation_unit_context tenv cfg procdesc immediate_curr_class return_param_typ let create_context translation_unit_context tenv cfg procdesc immediate_curr_class return_param_typ
is_immediate_objc_method outer_context vars_to_destroy = outer_context vars_to_destroy =
{ translation_unit_context { translation_unit_context
; tenv ; tenv
; cfg ; cfg
; procdesc ; procdesc
; immediate_curr_class ; immediate_curr_class
; return_param_typ ; return_param_typ
; is_immediate_objc_method
; outer_context ; outer_context
; blocks_static_vars= Typ.Procname.Map.empty ; blocks_static_vars= Typ.Procname.Map.empty
; label_map= Hashtbl.create 17 ; label_map= Hashtbl.create 17
@ -55,17 +53,17 @@ let rec is_objc_method context =
| Some outer_context -> | Some outer_context ->
is_objc_method outer_context is_objc_method outer_context
| None -> | None ->
context.is_immediate_objc_method context.procdesc |> Procdesc.get_proc_name |> Typ.Procname.is_objc_method
let rec is_objc_instance context = let rec is_objc_class_method context =
match context.outer_context with match context.outer_context with
| Some outer_context -> | Some outer_context ->
is_objc_instance outer_context is_objc_class_method outer_context
| None -> | None ->
let attrs = Procdesc.get_attributes context.procdesc in let attrs = Procdesc.get_attributes context.procdesc in
ProcAttributes.equal_clang_method_kind attrs.ProcAttributes.clang_method_kind ProcAttributes.equal_clang_method_kind attrs.ProcAttributes.clang_method_kind
ProcAttributes.OBJC_INSTANCE ProcAttributes.OBJC_CLASS
let rec get_curr_class context = let rec get_curr_class context =

@ -22,7 +22,6 @@ type t =
; tenv: Tenv.t ; tenv: Tenv.t
; cfg: Cfg.t ; cfg: Cfg.t
; procdesc: Procdesc.t ; procdesc: Procdesc.t
; is_immediate_objc_method: bool
; immediate_curr_class: curr_class ; immediate_curr_class: curr_class
; return_param_typ: Typ.t option ; return_param_typ: Typ.t option
; outer_context: t option ; outer_context: t option
@ -42,12 +41,12 @@ val get_curr_class_decl_ptr : Clang_ast_t.stmt_info -> curr_class -> Clang_ast_t
val is_objc_method : t -> bool val is_objc_method : t -> bool
val is_objc_class_method : t -> bool
val create_context : val create_context :
CFrontend_config.translation_unit_context -> Tenv.t -> Cfg.t -> Procdesc.t -> curr_class CFrontend_config.translation_unit_context -> Tenv.t -> Cfg.t -> Procdesc.t -> curr_class
-> Typ.t option -> bool -> t option -> Clang_ast_t.decl list StmtMap.t -> t -> Typ.t option -> t option -> Clang_ast_t.decl list StmtMap.t -> t
val add_block_static_var : t -> Typ.Procname.t -> Pvar.t * Typ.t -> unit val add_block_static_var : t -> Typ.Procname.t -> Pvar.t * Typ.t -> unit
val is_objc_instance : t -> bool
val get_outer_procname : t -> Typ.Procname.t val get_outer_procname : t -> Typ.Procname.t

@ -45,7 +45,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
(** Translates the method/function's body into nodes of the cfg. *) (** Translates the method/function's body into nodes of the cfg. *)
let add_method ?(is_destructor_wrapper= false) trans_unit_ctx tenv cfg class_decl_opt procname let add_method ?(is_destructor_wrapper= false) trans_unit_ctx tenv cfg class_decl_opt procname
body ms has_return_param is_objc_method outer_context_opt extra_instrs = body ms has_return_param outer_context_opt extra_instrs =
L.(debug Capture Verbose) L.(debug Capture Verbose)
"@\n@\n>>---------- ADDING METHOD: '%a' ---------<<@\n@\n" Typ.Procname.pp procname ; "@\n@\n>>---------- ADDING METHOD: '%a' ---------<<@\n@\n" Typ.Procname.pp procname ;
incr CFrontend_config.procedures_attempted ; incr CFrontend_config.procedures_attempted ;
@ -65,7 +65,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
let vars_to_destroy = CTrans_utils.Scope.compute_vars_to_destroy body in let vars_to_destroy = CTrans_utils.Scope.compute_vars_to_destroy body in
let context = let context =
CContext.create_context trans_unit_ctx tenv cfg procdesc class_decl_opt CContext.create_context trans_unit_ctx tenv cfg procdesc class_decl_opt
has_return_param is_objc_method outer_context_opt vars_to_destroy has_return_param outer_context_opt vars_to_destroy
in in
let start_node = Procdesc.get_start_node procdesc in let start_node = Procdesc.get_start_node procdesc in
let exit_node = Procdesc.get_exit_node procdesc in let exit_node = Procdesc.get_exit_node procdesc in
@ -121,7 +121,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
if CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] captured_vars if CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] captured_vars
then then
add_method trans_unit_ctx tenv cfg CContext.ContextNoCls procname body ms add_method trans_unit_ctx tenv cfg CContext.ContextNoCls procname body ms
return_param_typ_opt false outer_context_opt extra_instrs return_param_typ_opt outer_context_opt extra_instrs
| None -> | None ->
() ()
with CFrontend_config.IncorrectAssumption e -> with CFrontend_config.IncorrectAssumption e ->
@ -130,7 +130,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
let process_method_decl ?(set_objc_accessor_attr= false) ?(is_destructor= false) trans_unit_ctx let process_method_decl ?(set_objc_accessor_attr= false) ?(is_destructor= false) trans_unit_ctx
tenv cfg curr_class meth_decl ~is_objc = tenv cfg curr_class meth_decl =
try try
let ms, body_opt, extra_instrs = let ms, body_opt, extra_instrs =
let procname = CType_decl.CProcname.from_decl ~tenv meth_decl in let procname = CType_decl.CProcname.from_decl ~tenv meth_decl in
@ -150,7 +150,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
ms [body] [] ms [body] []
then then
add_method trans_unit_ctx tenv cfg curr_class procname body ms return_param_typ_opt add_method trans_unit_ctx tenv cfg curr_class procname body ms return_param_typ_opt
is_objc None extra_instrs ~is_destructor_wrapper:true ; None extra_instrs ~is_destructor_wrapper:true ;
let new_method_name = let new_method_name =
Config.clang_inner_destructor_prefix ^ Typ.Procname.get_method procname Config.clang_inner_destructor_prefix ^ Typ.Procname.get_method procname
in in
@ -166,7 +166,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
[body] [] [body] []
then then
add_method trans_unit_ctx tenv cfg curr_class procname' body ms' return_param_typ_opt add_method trans_unit_ctx tenv cfg curr_class procname' body ms' return_param_typ_opt
is_objc None extra_instrs ~is_destructor_wrapper:false None extra_instrs ~is_destructor_wrapper:false
| None -> | None ->
if set_objc_accessor_attr then if set_objc_accessor_attr then
ignore ignore
@ -186,7 +186,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
match CAst_utils.get_decl_opt_with_decl_ref pointer with match CAst_utils.get_decl_opt_with_decl_ref pointer with
| Some (ObjCMethodDecl _ as dec) -> | Some (ObjCMethodDecl _ as dec) ->
process_method_decl ~set_objc_accessor_attr:true trans_unit_ctx tenv cfg curr_class process_method_decl ~set_objc_accessor_attr:true trans_unit_ctx tenv cfg curr_class
dec ~is_objc:true dec
| _ -> | _ ->
() ()
in in
@ -200,12 +200,11 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
let open Clang_ast_t in let open Clang_ast_t in
match dec with match dec with
| CXXMethodDecl _ | CXXConstructorDecl _ | CXXConversionDecl _ -> | CXXMethodDecl _ | CXXConstructorDecl _ | CXXConversionDecl _ ->
process_method_decl trans_unit_ctx tenv cfg curr_class dec ~is_objc:false process_method_decl trans_unit_ctx tenv cfg curr_class dec
| CXXDestructorDecl _ -> | CXXDestructorDecl _ ->
process_method_decl trans_unit_ctx tenv cfg curr_class dec ~is_objc:false process_method_decl trans_unit_ctx tenv cfg curr_class dec ~is_destructor:true
~is_destructor:true
| ObjCMethodDecl _ -> | ObjCMethodDecl _ ->
process_method_decl trans_unit_ctx tenv cfg curr_class dec ~is_objc:true process_method_decl trans_unit_ctx tenv cfg curr_class dec
| ObjCPropertyImplDecl (_, obj_c_property_impl_decl_info) -> | ObjCPropertyImplDecl (_, obj_c_property_impl_decl_info) ->
process_property_implementation trans_unit_ctx tenv cfg curr_class process_property_implementation trans_unit_ctx tenv cfg curr_class
obj_c_property_impl_decl_info obj_c_property_impl_decl_info
@ -429,8 +428,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
in in
let body = Clang_ast_t.DeclStmt (stmt_info, [], [dec]) in let body = Clang_ast_t.DeclStmt (stmt_info, [], [dec]) in
ignore (CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] []) ; ignore (CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] []) ;
add_method trans_unit_ctx tenv cfg CContext.ContextNoCls procname body ms None false add_method trans_unit_ctx tenv cfg CContext.ContextNoCls procname body ms None None []
None []
(* Note that C and C++ records are treated the same way (* Note that C and C++ records are treated the same way
Skip translating implicit struct declarations, unless they have Skip translating implicit struct declarations, unless they have
full definition (which happens with C++ lambdas) *) full definition (which happens with C++ lambdas) *)

@ -2680,8 +2680,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let lambda_pname = CMethod_trans.get_procname_from_cpp_lambda context lei_lambda_decl in let lambda_pname = CMethod_trans.get_procname_from_cpp_lambda context lei_lambda_decl in
let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in
let get_captured_pvar_typ decl_ref = let get_captured_pvar_typ decl_ref =
CVar_decl.sil_var_of_captured_var decl_ref context stmt_info.Clang_ast_t.si_source_range Option.value_exn
procname (CVar_decl.sil_var_of_captured_var context stmt_info.Clang_ast_t.si_source_range procname
decl_ref)
in in
let translate_capture_init (pvar, typ) init_decl = let translate_capture_init (pvar, typ) init_decl =
match init_decl with match init_decl with

@ -75,25 +75,43 @@ let add_var_to_locals procdesc var_decl typ pvar =
assert false assert false
let sil_var_of_captured_var decl_ref context source_range procname = (* The context here is of the method that contains the block *)
match decl_ref with let sil_var_of_captured_var context source_range procname decl_ref =
| {Clang_ast_t.dr_qual_type= Some qual_type} -> let is_block_inside_objc_class_method = CContext.is_objc_class_method context in
( sil_var_of_decl_ref context source_range decl_ref procname let var_opt =
, CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type ) match decl_ref with
| {Clang_ast_t.dr_name= Some {Clang_ast_t.ni_name}} ->
(* In Objective-C class methods, self is not the standard self instance, since in this
context we don't have an instance. Instead it is used to get the class of the method.
We translate this variables in a different way than normal, we don't treat them as
variables in Sil, instead we remove them and get the class directly in the frontend.
For that reason, we shouldn't add them as captured variables of blocks, since they
don't appear anywhere else in the translation. *)
if is_block_inside_objc_class_method && String.equal ni_name CFrontend_config.self then
None
else Some (sil_var_of_decl_ref context source_range decl_ref procname)
| _ ->
assert false
in
let typ_opt =
CType_decl.type_of_captured_var context.CContext.tenv ~is_block_inside_objc_class_method
decl_ref
in
match (var_opt, typ_opt) with
| Some var, Some typ ->
Some (var, typ)
| None, None ->
None
| _ -> | _ ->
assert false Logging.die InternalError
"Not possible case, captured variable and its type should both be available or not at %s"
(Clang_ast_j.string_of_source_range source_range)
(* Returns a list of captured variables as sil variables. *) (* Returns a list of captured variables as sil variables. *)
let captured_vars_from_block_info context source_range cvl = let captured_vars_from_block_info context source_range captured_vars =
let procname = Procdesc.get_proc_name context.CContext.procdesc in let procname = Procdesc.get_proc_name context.CContext.procdesc in
let sil_var_of_captured_var {Clang_ast_t.bcv_variable} vars_acc = let cv_decl_ref_list =
match bcv_variable with List.map ~f:(fun cv -> Option.value_exn cv.Clang_ast_t.bcv_variable) captured_vars
| Some ({Clang_ast_t.dr_name= Some {Clang_ast_t.ni_name}} as decl_ref) ->
if String.equal ni_name CFrontend_config.self && not (CContext.is_objc_instance context)
then vars_acc
else sil_var_of_captured_var decl_ref context source_range procname :: vars_acc
| _ ->
assert false
in in
List.fold_right ~f:sil_var_of_captured_var cvl ~init:[] List.filter_map ~f:(sil_var_of_captured_var context source_range procname) cv_decl_ref_list

@ -19,8 +19,8 @@ val sil_var_of_decl_ref :
val add_var_to_locals : Procdesc.t -> Clang_ast_t.decl -> Typ.t -> Pvar.t -> unit val add_var_to_locals : Procdesc.t -> Clang_ast_t.decl -> Typ.t -> Pvar.t -> unit
val sil_var_of_captured_var : val sil_var_of_captured_var :
Clang_ast_t.decl_ref -> CContext.t -> Clang_ast_t.source_range -> Typ.Procname.t CContext.t -> Clang_ast_t.source_range -> Typ.Procname.t -> Clang_ast_t.decl_ref
-> Pvar.t * Typ.typ -> (Pvar.t * Typ.typ) option
val captured_vars_from_block_info : val captured_vars_from_block_info :
CContext.t -> Clang_ast_t.source_range -> Clang_ast_t.block_captured_variable list CContext.t -> Clang_ast_t.source_range -> Clang_ast_t.block_captured_variable list

@ -84,6 +84,7 @@ codetoanalyze/objc/errors/npe/block.m, BlockA_foo3:, 3, NULL_DEREFERENCE, B1, ER
codetoanalyze/objc/errors/npe/block.m, BlockA_foo4:, 6, NULL_DEREFERENCE, B1, ERROR, [start of procedure foo4:] codetoanalyze/objc/errors/npe/block.m, BlockA_foo4:, 6, NULL_DEREFERENCE, B1, ERROR, [start of procedure foo4:]
codetoanalyze/objc/errors/npe/block.m, BlockA_foo7, 2, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure foo7] codetoanalyze/objc/errors/npe/block.m, BlockA_foo7, 2, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure foo7]
codetoanalyze/objc/errors/npe/dynamic_dispatch.m, DynamicDispatchMain_npe_bad, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure npe_bad,start of procedure get_ddclass_from:,start of procedure get_ddclass,return from a call to PInstance_get_ddclass,return from a call to DynamicDispatchMain_get_ddclass_from:] codetoanalyze/objc/errors/npe/dynamic_dispatch.m, DynamicDispatchMain_npe_bad, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure npe_bad,start of procedure get_ddclass_from:,start of procedure get_ddclass,return from a call to PInstance_get_ddclass,return from a call to DynamicDispatchMain_get_ddclass_from:]
codetoanalyze/objc/errors/npe/dynamic_dispatch.m, objc_blockDynamicDispatchMain_dispatch_async_block_npe_bad_1, 3, NULL_DEREFERENCE, B5, ERROR, [start of procedure block,start of procedure get_ddclass_from:,start of procedure get_ddclass,return from a call to PInstance_get_ddclass,return from a call to DynamicDispatchMain_get_ddclass_from:]
codetoanalyze/objc/errors/npe/ivar_blocks.m, MyClass_ivar_npe, 1, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure ivar_npe] codetoanalyze/objc/errors/npe/ivar_blocks.m, MyClass_ivar_npe, 1, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure ivar_npe]
codetoanalyze/objc/errors/npe/skip_method_with_nil_object.m, SkipMethodNilA_testBug:, 6, PARAMETER_NOT_NULL_CHECKED, B2, WARNING, [start of procedure testBug:,Message get_a with receiver nil returns nil.,Message skip_method with receiver nil returns nil.,Taking false branch] codetoanalyze/objc/errors/npe/skip_method_with_nil_object.m, SkipMethodNilA_testBug:, 6, PARAMETER_NOT_NULL_CHECKED, B2, WARNING, [start of procedure testBug:,Message get_a with receiver nil returns nil.,Message skip_method with receiver nil returns nil.,Taking false branch]
codetoanalyze/objc/errors/property/main.c, property_main, 3, MEMORY_LEAK, no_bucket, ERROR, [start of procedure property_main(),Skipping aProperty: method has no implementation] codetoanalyze/objc/errors/property/main.c, property_main, 3, MEMORY_LEAK, no_bucket, ERROR, [start of procedure property_main(),Skipping aProperty: method has no implementation]

@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
#import <Foundation/NSObject.h> #import <Foundation/Foundation.h>
@interface DynamicDispatchClass : NSObject @interface DynamicDispatchClass : NSObject
@end @end
@ -49,4 +49,14 @@
return [self get_ddclass_from:object] -> x; return [self get_ddclass_from:object] -> x;
} }
+ (int)dispatch_async_block_npe_bad {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
PInstance* object = [PInstance new];
DynamicDispatchMain* main = [DynamicDispatchMain new];
int x = [main get_ddclass_from:object] -> x;
});
return 0;
}
@end @end

@ -34,17 +34,17 @@ digraph cfg {
"main.fad58de7366495db4650cfefac2fcd61_5" -> "main.fad58de7366495db4650cfefac2fcd61_4" ; "main.fad58de7366495db4650cfefac2fcd61_5" -> "main.fad58de7366495db4650cfefac2fcd61_4" ;
"objc_blockA_capture_1(class D).ce4342d16a7487aa29e55ea807813fe8_1" [label="1: Start objc_blockA_capture_1\nFormals: self:A* d:D*\nLocals: \nCaptured: self:A* \n DECLARE_LOCALS(&return); [line 45, column 16]\n " color=yellow style=filled] "objc_blockA_capture_1(class A,class D).d4c908ef76f37b34ec8aa31647489ab4_1" [label="1: Start objc_blockA_capture_1\nFormals: self:A* d:D*\nLocals: \nCaptured: self:A* \n DECLARE_LOCALS(&return); [line 45, column 16]\n " color=yellow style=filled]
"objc_blockA_capture_1(class D).ce4342d16a7487aa29e55ea807813fe8_1" -> "objc_blockA_capture_1(class D).ce4342d16a7487aa29e55ea807813fe8_3" ; "objc_blockA_capture_1(class A,class D).d4c908ef76f37b34ec8aa31647489ab4_1" -> "objc_blockA_capture_1(class A,class D).d4c908ef76f37b34ec8aa31647489ab4_3" ;
"objc_blockA_capture_1(class D).ce4342d16a7487aa29e55ea807813fe8_2" [label="2: Exit objc_blockA_capture_1 \n " color=yellow style=filled] "objc_blockA_capture_1(class A,class D).d4c908ef76f37b34ec8aa31647489ab4_2" [label="2: Exit objc_blockA_capture_1 \n " color=yellow style=filled]
"objc_blockA_capture_1(class D).ce4342d16a7487aa29e55ea807813fe8_3" [label="3: BinaryOperatorStmt: Assign \n n$1=*&self:A* [line 46, column 5]\n n$2=*&d:D* [line 46, column 13]\n *n$1._data:D*=n$2 [line 46, column 5]\n " shape="box"] "objc_blockA_capture_1(class A,class D).d4c908ef76f37b34ec8aa31647489ab4_3" [label="3: BinaryOperatorStmt: Assign \n n$1=*&self:A* [line 46, column 5]\n n$2=*&d:D* [line 46, column 13]\n *n$1._data:D*=n$2 [line 46, column 5]\n " shape="box"]
"objc_blockA_capture_1(class D).ce4342d16a7487aa29e55ea807813fe8_3" -> "objc_blockA_capture_1(class D).ce4342d16a7487aa29e55ea807813fe8_2" ; "objc_blockA_capture_1(class A,class D).d4c908ef76f37b34ec8aa31647489ab4_3" -> "objc_blockA_capture_1(class A,class D).d4c908ef76f37b34ec8aa31647489ab4_2" ;
"capture#A#instance.d411336575e4bf632a1828f5f5979726_1" [label="1: Start A_capture\nFormals: self:A*\nLocals: \n DECLARE_LOCALS(&return); [line 43, column 1]\n " color=yellow style=filled] "capture#A#instance.d411336575e4bf632a1828f5f5979726_1" [label="1: Start A_capture\nFormals: self:A*\nLocals: \n DECLARE_LOCALS(&return); [line 43, column 1]\n " color=yellow style=filled]

@ -1,16 +1,16 @@
/* @generated */ /* @generated */
digraph cfg { digraph cfg {
"objc_blockB_f_1.9ca2cd9875647cc0e2a4803d22445f9c_1" [label="1: Start objc_blockB_f_1\nFormals: self:B* const \nLocals: \nCaptured: self:B* const \n DECLARE_LOCALS(&return); [line 24, column 11]\n " color=yellow style=filled] "objc_blockB_f_1(class B).6b5af83d1cf19e8038483ea8b08b7439_1" [label="1: Start objc_blockB_f_1\nFormals: self:B* const \nLocals: \nCaptured: self:B* const \n DECLARE_LOCALS(&return); [line 24, column 11]\n " color=yellow style=filled]
"objc_blockB_f_1.9ca2cd9875647cc0e2a4803d22445f9c_1" -> "objc_blockB_f_1.9ca2cd9875647cc0e2a4803d22445f9c_3" ; "objc_blockB_f_1(class B).6b5af83d1cf19e8038483ea8b08b7439_1" -> "objc_blockB_f_1(class B).6b5af83d1cf19e8038483ea8b08b7439_3" ;
"objc_blockB_f_1.9ca2cd9875647cc0e2a4803d22445f9c_2" [label="2: Exit objc_blockB_f_1 \n " color=yellow style=filled] "objc_blockB_f_1(class B).6b5af83d1cf19e8038483ea8b08b7439_2" [label="2: Exit objc_blockB_f_1 \n " color=yellow style=filled]
"objc_blockB_f_1.9ca2cd9875647cc0e2a4803d22445f9c_3" [label="3: BinaryOperatorStmt: Assign \n n$3=*&self:B* [line 25, column 9]\n *n$3.x:int=5 [line 25, column 9]\n " shape="box"] "objc_blockB_f_1(class B).6b5af83d1cf19e8038483ea8b08b7439_3" [label="3: BinaryOperatorStmt: Assign \n n$3=*&self:B* [line 25, column 9]\n *n$3.x:int=5 [line 25, column 9]\n " shape="box"]
"objc_blockB_f_1.9ca2cd9875647cc0e2a4803d22445f9c_3" -> "objc_blockB_f_1.9ca2cd9875647cc0e2a4803d22445f9c_2" ; "objc_blockB_f_1(class B).6b5af83d1cf19e8038483ea8b08b7439_3" -> "objc_blockB_f_1(class B).6b5af83d1cf19e8038483ea8b08b7439_2" ;
"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_1" [label="1: Start B_f\nFormals: self:B*\nLocals: \n DECLARE_LOCALS(&return); [line 22, column 1]\n " color=yellow style=filled] "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_1" [label="1: Start B_f\nFormals: self:B*\nLocals: \n DECLARE_LOCALS(&return); [line 22, column 1]\n " color=yellow style=filled]

@ -1,33 +1,33 @@
/* @generated */ /* @generated */
digraph cfg { digraph cfg {
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_1" [label="1: Start objc_blockMy_manager_blockReleaseNoLeak_1\nFormals: newImage:CGImage* a:int\nLocals: \nCaptured: newImage:CGImage* \n DECLARE_LOCALS(&return); [line 23, column 7]\n " color=yellow style=filled] "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_1" [label="1: Start objc_blockMy_manager_blockReleaseNoLeak_1\nFormals: newImage:CGImage* a:int\nLocals: \nCaptured: newImage:CGImage* \n DECLARE_LOCALS(&return); [line 23, column 7]\n " color=yellow style=filled]
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_1" -> "objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_5" ; "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_1" -> "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_5" ;
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_1" -> "objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_6" ; "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_1" -> "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_6" ;
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_2" [label="2: Exit objc_blockMy_manager_blockReleaseNoLeak_1 \n " color=yellow style=filled] "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_2" [label="2: Exit objc_blockMy_manager_blockReleaseNoLeak_1 \n " color=yellow style=filled]
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_3" [label="3: + \n " ] "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_3" [label="3: + \n " ]
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_3" -> "objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_4" ; "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_3" -> "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_4" ;
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_4" [label="4: between_join_and_exit \n " shape="box"] "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_4" [label="4: between_join_and_exit \n " shape="box"]
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_4" -> "objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_2" ; "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_4" -> "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_2" ;
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_5" [label="5: Prune (true branch, if) \n n$10=*&newImage:CGImage* [line 24, column 9]\n PRUNE(n$10, true); [line 24, column 9]\n " shape="invhouse"] "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_5" [label="5: Prune (true branch, if) \n n$10=*&newImage:CGImage* [line 24, column 9]\n PRUNE(n$10, true); [line 24, column 9]\n " shape="invhouse"]
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_5" -> "objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_7" ; "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_5" -> "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_7" ;
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_6" [label="6: Prune (false branch, if) \n n$10=*&newImage:CGImage* [line 24, column 9]\n PRUNE(!n$10, false); [line 24, column 9]\n " shape="invhouse"] "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_6" [label="6: Prune (false branch, if) \n n$10=*&newImage:CGImage* [line 24, column 9]\n PRUNE(!n$10, false); [line 24, column 9]\n " shape="invhouse"]
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_6" -> "objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_3" ; "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_6" -> "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_3" ;
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_7" [label="7: Call _fun_CGImageRelease \n n$11=*&newImage:CGImage* [line 25, column 22]\n n$12=_fun_CGImageRelease(n$11:CGImage*) [line 25, column 7]\n " shape="box"] "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_7" [label="7: Call _fun_CGImageRelease \n n$11=*&newImage:CGImage* [line 25, column 22]\n n$12=_fun_CGImageRelease(n$11:CGImage*) [line 25, column 7]\n " shape="box"]
"objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_7" -> "objc_blockMy_manager_blockReleaseNoLeak_1.a1f2f2c370e78fee994cf9a9d53a7210_3" ; "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_7" -> "objc_blockMy_manager_blockReleaseNoLeak_1(struct CGImage).d9015a9be6e156b53b1e0a2e237f4578_3" ;
"blockReleaseNoLeak#My_manager#instance.0c48f80f024250b18a529440f1313af6_1" [label="1: Start My_manager_blockReleaseNoLeak\nFormals: self:My_manager*\nLocals: newImage:CGImage* context:CGContext* z:int b:_fn_(*) \n DECLARE_LOCALS(&return,&newImage,&context,&z,&b); [line 18, column 1]\n " color=yellow style=filled] "blockReleaseNoLeak#My_manager#instance.0c48f80f024250b18a529440f1313af6_1" [label="1: Start My_manager_blockReleaseNoLeak\nFormals: self:My_manager*\nLocals: newImage:CGImage* context:CGContext* z:int b:_fn_(*) \n DECLARE_LOCALS(&return,&newImage,&context,&z,&b); [line 18, column 1]\n " color=yellow style=filled]

@ -44,17 +44,17 @@ digraph cfg {
"DispatchMain.f6461dbdaeaf9a114cbe40f5f72fbb3f_11" -> "DispatchMain.f6461dbdaeaf9a114cbe40f5f72fbb3f_10" ; "DispatchMain.f6461dbdaeaf9a114cbe40f5f72fbb3f_11" -> "DispatchMain.f6461dbdaeaf9a114cbe40f5f72fbb3f_10" ;
"objc_blockDispatchA_block_attribute_2.871f06a0b12b5767153a5d30f3798261_1" [label="1: Start objc_blockDispatchA_block_attribute_2\nFormals: a:DispatchA*\nLocals: \nCaptured: a:DispatchA* \n DECLARE_LOCALS(&return); [line 37, column 24]\n " color=yellow style=filled] "objc_blockDispatchA_block_attribute_2(class DispatchA).2825198b53dffef0e3209a90789e506f_1" [label="1: Start objc_blockDispatchA_block_attribute_2\nFormals: a:DispatchA*\nLocals: \nCaptured: a:DispatchA* \n DECLARE_LOCALS(&return); [line 37, column 24]\n " color=yellow style=filled]
"objc_blockDispatchA_block_attribute_2.871f06a0b12b5767153a5d30f3798261_1" -> "objc_blockDispatchA_block_attribute_2.871f06a0b12b5767153a5d30f3798261_3" ; "objc_blockDispatchA_block_attribute_2(class DispatchA).2825198b53dffef0e3209a90789e506f_1" -> "objc_blockDispatchA_block_attribute_2(class DispatchA).2825198b53dffef0e3209a90789e506f_3" ;
"objc_blockDispatchA_block_attribute_2.871f06a0b12b5767153a5d30f3798261_2" [label="2: Exit objc_blockDispatchA_block_attribute_2 \n " color=yellow style=filled] "objc_blockDispatchA_block_attribute_2(class DispatchA).2825198b53dffef0e3209a90789e506f_2" [label="2: Exit objc_blockDispatchA_block_attribute_2 \n " color=yellow style=filled]
"objc_blockDispatchA_block_attribute_2.871f06a0b12b5767153a5d30f3798261_3" [label="3: BinaryOperatorStmt: Assign \n n$8=*&a:DispatchA* [line 38, column 5]\n *n$8._x:int=10 [line 38, column 5]\n " shape="box"] "objc_blockDispatchA_block_attribute_2(class DispatchA).2825198b53dffef0e3209a90789e506f_3" [label="3: BinaryOperatorStmt: Assign \n n$8=*&a:DispatchA* [line 38, column 5]\n *n$8._x:int=10 [line 38, column 5]\n " shape="box"]
"objc_blockDispatchA_block_attribute_2.871f06a0b12b5767153a5d30f3798261_3" -> "objc_blockDispatchA_block_attribute_2.871f06a0b12b5767153a5d30f3798261_2" ; "objc_blockDispatchA_block_attribute_2(class DispatchA).2825198b53dffef0e3209a90789e506f_3" -> "objc_blockDispatchA_block_attribute_2(class DispatchA).2825198b53dffef0e3209a90789e506f_2" ;
"objc_blockDispatchA_dispatch_a_block_variable_4.2eedc45fca2c35e6e8c11937ba7a2df8_1" [label="1: Start objc_blockDispatchA_dispatch_a_block_variable_4\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 54, column 38]\n " color=yellow style=filled] "objc_blockDispatchA_dispatch_a_block_variable_4.2eedc45fca2c35e6e8c11937ba7a2df8_1" [label="1: Start objc_blockDispatchA_dispatch_a_block_variable_4\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 54, column 38]\n " color=yellow style=filled]

Loading…
Cancel
Save