You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
infer_clone/infer/src/checkers/fragmentRetainsViewChecker.ml

66 lines
2.9 KiB

(*
* Copyright (c) 2013 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
(** Make sure callbacks are always unregistered. drive the point home by reporting possible NPE's *)
module P = Printf
let report_error fragment_typ fld fld_typ pname pdesc =
let retained_view = "CHECKERS_FRAGMENT_RETAINS_VIEW" in
let description = Localise.desc_fragment_retains_view fragment_typ fld fld_typ pname in
let exn = Exceptions.Checkers (retained_view, description) in
let loc = Cfg.Procdesc.get_loc pdesc in
Reporting.log_error pname ~loc:(Some loc) exn
let callback_fragment_retains_view_java
pname_java { Callbacks.proc_desc; 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 = Procname.java_get_method pname_java = "onDestroyView" in
(* this is needlessly complicated because field types are Tvars instead of Tstructs *)
let fld_typ_is_view = function
| Sil.Tptr (Sil.Tvar tname, _) ->
begin
match Sil.tenv_lookup tenv tname with
| Some struct_typ -> AndroidFramework.is_view (Sil.Tstruct struct_typ) tenv
| None -> false
end
| _ -> false in
(* is [fldname] a View type declared by [class_typename]? *)
let is_declared_view_typ class_typename (fldname, fld_typ, _) =
let fld_classname = Typename.Java.from_string (Ident.java_fieldname_get_class fldname) in
Typename.equal fld_classname class_typename && fld_typ_is_view fld_typ in
if is_on_destroy_view then
begin
let class_typename =
Typename.Java.from_string (Procname.java_get_class_name pname_java) in
match Sil.tenv_lookup tenv class_typename with
| Some ({ Sil.struct_name = Some _; instance_fields } as struct_typ)
when AndroidFramework.is_fragment (Sil.Tstruct struct_typ) tenv ->
let declared_view_fields =
IList.filter (is_declared_view_typ class_typename) instance_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 *)
IList.iter
(fun (fname, fld_typ, _) ->
if not (Ident.FieldSet.mem fname fields_nullified) then
report_error
(Sil.Tstruct struct_typ) fname fld_typ
(Procname.Java pname_java) proc_desc)
declared_view_fields
| _ -> ()
end
let callback_fragment_retains_view ({ Callbacks.proc_name } as args) =
match proc_name with
| Procname.Java pname_java ->
callback_fragment_retains_view_java pname_java args
| _ ->
()