diff --git a/infer/src/checkers/fragmentRetainsViewChecker.ml b/infer/src/checkers/fragmentRetainsViewChecker.ml index 5e95a0914..cc07d5d9d 100644 --- a/infer/src/checkers/fragmentRetainsViewChecker.ml +++ b/infer/src/checkers/fragmentRetainsViewChecker.ml @@ -9,6 +9,10 @@ open! IStd (** Make sure callbacks are always unregistered. drive the point home by reporting possible NPE's *) +let on_create_view = "onCreateView" + +let on_destroy_view = "onDestroyView" + let rec format_typ typ = match typ.Typ.desc with | Typ.Tptr (t, _) when Language.curr_language_is Java -> @@ -19,11 +23,6 @@ let rec format_typ typ = Typ.to_string typ -let format_field f = - if Language.curr_language_is Java then Typ.Fieldname.Java.get_field f - else Typ.Fieldname.to_string f - - let format_method pname = match pname with | Typ.Procname.Java pname_java -> @@ -32,24 +31,27 @@ let format_method pname = Typ.Procname.to_string pname -let report_warning fragment_typ fld fld_typ summary pdesc = - let pname = Procdesc.get_proc_name pdesc in +let report_warning class_name fld fld_typ summary = + let pname = Summary.get_proc_name summary in + let loc = Summary.get_loc summary in + let pp_m = MarkupFormatter.pp_monospaced in let description = - Printf.sprintf - "Fragment %s does not nullify View field %s (type %s) in %s. If this Fragment is placed on \ + Format.asprintf + "Fragment %a does not nullify View field %a (type %a) in %a. If this Fragment is placed on \ the back stack, a reference to this (probably dead) View will be retained. In general, it \ - is a good idea to initialize View's in onCreateView, then nullify them in onDestroyView." - (format_typ fragment_typ) (format_field fld) (format_typ fld_typ) (format_method pname) + is a good idea to initialize View's in %a, then nullify them in %a." + pp_m (Typ.Name.name class_name) pp_m + (Typ.Fieldname.to_flat_string fld) + pp_m (format_typ fld_typ) pp_m (format_method pname) pp_m on_create_view pp_m on_destroy_view in - let loc = Procdesc.get_loc pdesc in Reporting.log_warning summary ~loc IssueType.checkers_fragment_retain_view description -let callback_fragment_retains_view_java pname_java {Callbacks.proc_desc; summary; tenv} = +let callback_fragment_retains_view_java java_pname {Callbacks.proc_desc; summary; tenv} = (* TODO: complain if onDestroyView is not defined, yet the Fragment has View fields *) (* TODO: handle fields nullified in callees in the same file *) let is_on_destroy_view = - String.equal (Typ.Procname.Java.get_method pname_java) "onDestroyView" + String.equal (Typ.Procname.Java.get_method java_pname) on_destroy_view in let fld_typ_is_view typ = match typ.Typ.desc with @@ -64,10 +66,10 @@ let callback_fragment_retains_view_java pname_java {Callbacks.proc_desc; summary Typ.Name.equal fld_classname class_typename && fld_typ_is_view fld_typ in if is_on_destroy_view then - let class_typename = Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name pname_java) in - match Tenv.lookup tenv class_typename with - | Some {fields} when AndroidFramework.is_fragment tenv class_typename -> - let declared_view_fields = List.filter ~f:(is_declared_view_typ class_typename) fields in + let class_name = Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name java_pname) in + match Tenv.lookup tenv class_name with + | Some {fields} when AndroidFramework.is_fragment tenv class_name -> + let declared_view_fields = List.filter ~f:(is_declared_view_typ class_name) fields in let fields_nullified = PatternMatch.get_fields_nullified proc_desc in (* report if a field is declared by C, but not nulled out in C.onDestroyView *) List.iter @@ -76,8 +78,7 @@ let callback_fragment_retains_view_java pname_java {Callbacks.proc_desc; summary not ( Annotations.ia_ends_with ia Annotations.auto_cleanup || Typ.Fieldname.Set.mem fname fields_nullified ) - then report_warning (Typ.mk (Tstruct class_typename)) fname fld_typ summary proc_desc - ) + then report_warning class_name fname fld_typ summary ) declared_view_fields | _ -> () @@ -86,8 +87,8 @@ let callback_fragment_retains_view_java pname_java {Callbacks.proc_desc; summary let callback_fragment_retains_view ({Callbacks.summary} as args) : Summary.t = let proc_name = Summary.get_proc_name summary in ( match proc_name with - | Typ.Procname.Java pname_java -> - callback_fragment_retains_view_java pname_java args + | Typ.Procname.Java java_pname -> + callback_fragment_retains_view_java java_pname args | _ -> () ) ; summary