[checkers] move aggregation by class out of cluster checker callbacks

Summary:
A Java cluster checker currently defines a "cluster" as all of the procedures in the same class.
But the cluster checker actually knows about all the procedures defined in the same source file.
In some checkers (such as thread-safety), we want to aggregate results across classes in the same file, not just methods in the same class.
This refactoring leaves the behavior the same for now, but will make it easier to do this in the near future.

Reviewed By: jeremydubreil

Differential Revision: D5885896

fbshipit-source-id: 0815fca
master
Sam Blackshear 7 years ago committed by Facebook Github Bot
parent f1b97d5a89
commit 6a76bc6c7a

@ -80,9 +80,9 @@ let iterate_procedure_callbacks exe_env summary caller_pname =
!procedure_callbacks !procedure_callbacks
(** Invoke all registered cluster callbacks on a cluster of procedures. *) (** Invoke all registered cluster callbacks on a cluster of procedures. *)
let iterate_cluster_callbacks all_procs exe_env proc_names = let iterate_cluster_callbacks all_procs exe_env =
let get_procdesc = Exe_env.get_proc_desc exe_env in let get_procdesc = Exe_env.get_proc_desc exe_env in
let procedure_definitions = List.filter_map ~f:(get_procedure_definition exe_env) proc_names in let procedure_definitions = List.filter_map ~f:(get_procedure_definition exe_env) all_procs in
let environment = let environment =
List.map List.map
~f:(fun (idenv, tenv, proc_name, proc_desc, _) -> (idenv, tenv, proc_name, proc_desc)) ~f:(fun (idenv, tenv, proc_name, proc_desc, _) -> (idenv, tenv, proc_name, proc_desc))
@ -91,8 +91,8 @@ let iterate_cluster_callbacks all_procs exe_env proc_names =
(* Procedures matching the given language or all if no language is specified. *) (* Procedures matching the given language or all if no language is specified. *)
let relevant_procedures language_opt = let relevant_procedures language_opt =
Option.value_map Option.value_map
~f:(fun l -> List.filter ~f:(fun p -> Config.equal_language l (get_language p)) proc_names) ~f:(fun l -> List.filter ~f:(fun p -> Config.equal_language l (get_language p)) all_procs)
~default:proc_names language_opt ~default:all_procs language_opt
in in
List.iter List.iter
~f:(fun (language_opt, cluster_callback) -> ~f:(fun (language_opt, cluster_callback) ->
@ -133,32 +133,8 @@ let iterate_callbacks call_graph exe_env =
Ondemand.set_callbacks callbacks ; Ondemand.set_callbacks callbacks ;
(* Invoke procedure callbacks using on-demand anlaysis schedulling *) (* Invoke procedure callbacks using on-demand anlaysis schedulling *)
List.iter ~f:analyze_proc_name procs_to_analyze ; List.iter ~f:analyze_proc_name procs_to_analyze ;
let originally_defined_procs = Cg.get_defined_nodes call_graph in
let cluster_id proc_name =
match proc_name with
| Typ.Procname.Java pname_java
-> Typ.Procname.java_get_class_name pname_java
| _
-> "unknown"
in
let cluster proc_names =
let cluster_map =
List.fold
~f:(fun map proc_name ->
let proc_cluster = cluster_id proc_name in
let bucket =
try String.Map.find_exn map proc_cluster
with Not_found -> []
in
String.Map.add ~key:proc_cluster ~data:(proc_name :: bucket) map)
~init:String.Map.empty proc_names
in
(* Return all values of the map *)
String.Map.data cluster_map
in
(* Invoke cluster callbacks. *) (* Invoke cluster callbacks. *)
List.iter ~f:(iterate_cluster_callbacks originally_defined_procs exe_env) iterate_cluster_callbacks procs_to_analyze exe_env ;
(cluster procs_to_analyze) ;
(* Unregister callbacks *) (* Unregister callbacks *)
Ondemand.unset_callbacks () ; Ondemand.unset_callbacks () ;
Config.curr_language := saved_language Config.curr_language := saved_language

@ -1647,6 +1647,28 @@ let make_results_table file_env =
in in
List.fold ~f:aggregate_posts file_env ~init:AccessListMap.empty |> quotient_access_map List.fold ~f:aggregate_posts file_env ~init:AccessListMap.empty |> quotient_access_map
(* aggregate all of the procedures in the file env by their declaring class. this lets us analyze
each class individually *)
let aggregate_by_class file_env =
List.fold file_env
~f:(fun acc (_, _, pname, _ as proc) ->
let classname =
match pname with
| Typ.Procname.Java java_pname
-> Typ.Procname.java_get_class_name java_pname
| _
-> "unknown"
in
let bucket =
try String.Map.find_exn acc classname
with Not_found -> []
in
String.Map.add ~key:classname ~data:(proc :: bucket) acc)
~init:String.Map.empty
(* Gathers results by analyzing all the methods in a file, then post-processes the results to check (* Gathers results by analyzing all the methods in a file, then post-processes the results to check
an (approximation of) thread safety *) an (approximation of) thread safety *)
let file_analysis _ _ _ file_env = report_unsafe_accesses (make_results_table file_env) let file_analysis _ _ _ file_env =
String.Map.iter
~f:(fun class_env -> report_unsafe_accesses (make_results_table class_env))
(aggregate_by_class file_env)

Loading…
Cancel
Save