parent
28f5025862
commit
0f8c3e7974
@ -0,0 +1,110 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) 2015 - 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.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** Module for on-demand analysis. *)
|
||||||
|
|
||||||
|
module L = Logging
|
||||||
|
module F = Format
|
||||||
|
open Utils
|
||||||
|
|
||||||
|
let trace = false
|
||||||
|
|
||||||
|
let enabled () = false
|
||||||
|
|
||||||
|
type analyze_proc = Procname.t -> unit
|
||||||
|
|
||||||
|
type get_proc_desc = Procname.t -> Cfg.Procdesc.t option
|
||||||
|
|
||||||
|
let analyze_proc_fun = ref None
|
||||||
|
|
||||||
|
let set_analyze_proc (analyze_proc : analyze_proc) =
|
||||||
|
analyze_proc_fun := Some analyze_proc
|
||||||
|
|
||||||
|
let unset_analyze_prop () =
|
||||||
|
analyze_proc_fun := None
|
||||||
|
|
||||||
|
let do_analysis (get_proc_desc : get_proc_desc) curr_pname proc_name =
|
||||||
|
if trace then L.stderr "do_analysis %a -> %a@." Procname.pp curr_pname Procname.pp proc_name;
|
||||||
|
|
||||||
|
let really_do_analysis analyze_proc proc_desc =
|
||||||
|
L.stderr "really_do_analysis@.";
|
||||||
|
|
||||||
|
let preprocess () =
|
||||||
|
let attributes_opt =
|
||||||
|
Some (Cfg.Procdesc.get_attributes proc_desc) in
|
||||||
|
let call_graph =
|
||||||
|
let cg = Cg.create () in
|
||||||
|
Cg.add_node cg proc_name;
|
||||||
|
cg in
|
||||||
|
Specs.reset_summary call_graph proc_name attributes_opt;
|
||||||
|
Specs.set_status proc_name Specs.ACTIVE in
|
||||||
|
|
||||||
|
let postprocess () =
|
||||||
|
let summary = Specs.get_summary_unsafe proc_name in
|
||||||
|
let summary' =
|
||||||
|
{ summary with
|
||||||
|
Specs.status = Specs.INACTIVE;
|
||||||
|
timestamp = summary.Specs.timestamp + 1 } in
|
||||||
|
Specs.add_summary proc_name summary';
|
||||||
|
Checkers.ST.store_summary proc_name in
|
||||||
|
|
||||||
|
try
|
||||||
|
preprocess ();
|
||||||
|
analyze_proc proc_name;
|
||||||
|
postprocess ()
|
||||||
|
with e ->
|
||||||
|
L.stderr "ONDEMAND EXCEPTION %a %s %s@."
|
||||||
|
Procname.pp proc_name
|
||||||
|
(Printexc.to_string e)
|
||||||
|
(Printexc.get_backtrace ());
|
||||||
|
raise e in
|
||||||
|
|
||||||
|
let currently_analyzed =
|
||||||
|
Specs.summary_exists proc_name &&
|
||||||
|
Specs.is_active proc_name in
|
||||||
|
let already_analyzed = match Specs.get_summary proc_name with
|
||||||
|
| Some summary ->
|
||||||
|
Specs.get_timestamp summary > 0
|
||||||
|
| None ->
|
||||||
|
false in
|
||||||
|
(* The procedure to be analyzed is in the same file as the current one. *)
|
||||||
|
let same_file proc_desc =
|
||||||
|
match get_proc_desc curr_pname with
|
||||||
|
| Some curr_pdesc ->
|
||||||
|
(Cfg.Procdesc.get_loc curr_pdesc).Location.file
|
||||||
|
=
|
||||||
|
(Cfg.Procdesc.get_loc proc_desc).Location.file
|
||||||
|
| None -> false in
|
||||||
|
|
||||||
|
match !analyze_proc_fun, get_proc_desc proc_name with
|
||||||
|
| Some analyze_proc, Some proc_desc
|
||||||
|
when enabled () &&
|
||||||
|
Cfg.Procdesc.is_defined proc_desc && (* we have the implementation *)
|
||||||
|
not currently_analyzed && (* avoid infinite loops *)
|
||||||
|
not already_analyzed && (* avoid re-analysis of the same procedure *)
|
||||||
|
same_file proc_desc (* clusters don't have enough info for other files *) ->
|
||||||
|
really_do_analysis analyze_proc proc_desc
|
||||||
|
| _ ->
|
||||||
|
if trace then L.stderr "skipping@."
|
||||||
|
|
||||||
|
|
||||||
|
(** Mark the return type @Nullable by modifying the spec. *)
|
||||||
|
let proc_add_return_nullable curr_pname =
|
||||||
|
let summary = Specs.get_summary_unsafe curr_pname in
|
||||||
|
let proc_attributes = Specs.get_attributes summary in
|
||||||
|
let method_annotation = proc_attributes.ProcAttributes.method_annotation in
|
||||||
|
let method_annotation' = Annotations.method_annotation_mark_return
|
||||||
|
Annotations.Nullable method_annotation in
|
||||||
|
let proc_attributes' =
|
||||||
|
{ proc_attributes with
|
||||||
|
ProcAttributes.method_annotation = method_annotation' } in
|
||||||
|
let summary' =
|
||||||
|
{ summary with
|
||||||
|
Specs.attributes = proc_attributes' } in
|
||||||
|
Specs.add_summary curr_pname summary'
|
@ -0,0 +1,31 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) 2015 - 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.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** Module for on-demand analysis. *)
|
||||||
|
|
||||||
|
type analyze_proc = Procname.t -> unit
|
||||||
|
|
||||||
|
type get_proc_desc = Procname.t -> Cfg.Procdesc.t option
|
||||||
|
|
||||||
|
(** do_analysis get_proc_desc curr_pname proc_name
|
||||||
|
performs an on-demand analysis of proc_name
|
||||||
|
triggered during the analysis of curr_pname. *)
|
||||||
|
val do_analysis : get_proc_desc -> Procname.t -> Procname.t -> unit
|
||||||
|
|
||||||
|
(** Check if on-demand is currently active. *)
|
||||||
|
val enabled : unit -> bool
|
||||||
|
|
||||||
|
(** Mark the return type @Nullable by modifying the spec. *)
|
||||||
|
val proc_add_return_nullable : Procname.t -> unit
|
||||||
|
|
||||||
|
(** Set the function to be used to perform on-demand analysis. *)
|
||||||
|
val set_analyze_proc : analyze_proc -> unit
|
||||||
|
|
||||||
|
(** Unset the function to be used to perform on-demand analysis. *)
|
||||||
|
val unset_analyze_prop : unit -> unit
|
Loading…
Reference in new issue