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.
63 lines
2.9 KiB
63 lines
2.9 KiB
9 years ago
|
(*
|
||
|
* 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
|
||
|
open Utils
|
||
|
|
||
|
let report_error fld fld_typ pname pdesc =
|
||
|
let retained_view = "CHECKERS_FRAGMENT_RETAINS_VIEW" in
|
||
|
let fld_decl_class, fld_name =
|
||
|
Ident.java_fieldname_get_class fld, Ident.java_fieldname_get_field fld in
|
||
|
let description =
|
||
|
P.sprintf
|
||
|
"Fragment %s does not nullify View field %s (type %s) in onDestroyView. If the Fragment is placed on the back stack, a reference to the View may be retained."
|
||
|
fld_decl_class
|
||
|
fld_name
|
||
|
(Sil.typ_to_string (Sil.typ_strip_ptr fld_typ)) in
|
||
|
let loc = Cfg.Procdesc.get_loc pdesc in
|
||
|
let exn = Exceptions.Checkers (retained_view, Localise.verbatim_desc description) in
|
||
|
Reporting.log_error pname ~loc:(Some loc) exn
|
||
|
|
||
|
let callback_fragment_retains_view all_procs get_procdesc idenv tenv pname pdesc =
|
||
|
(* 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 = "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 typ -> AndroidFramework.is_view 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 pname) in
|
||
|
match Sil.tenv_lookup tenv class_typename with
|
||
|
| Some (Sil.Tstruct { Sil.csu; struct_name = Some class_name; def_methods; instance_fields }
|
||
|
as typ) when AndroidFramework.is_fragment typ tenv ->
|
||
|
let declared_view_fields =
|
||
|
IList.filter (is_declared_view_typ class_typename) instance_fields in
|
||
|
let fields_nullified = PatternMatch.get_fields_nullified pdesc in
|
||
|
(* report if a field is declared by C, but not nulled out in C.onDestroyView *)
|
||
|
IList.iter
|
||
|
(fun (fname, typ, _) ->
|
||
|
if not (Ident.FieldSet.mem fname fields_nullified) then
|
||
|
report_error fname typ pname pdesc)
|
||
|
declared_view_fields
|
||
|
| _ -> ()
|
||
|
end
|