add matchers from inferconfig to the CLI

Summary:
Part of the migration of .inferconfig-specific options into options accepted
both by .inferconfig and the CLI.

This changes the behaviour of Infer in that we now create matchers eagerly
instead of lazily. I think it's ok because I suspect what's really important is
not laziness but memoisation, and thus laziness was just an implementation
detail. If I'm wrong please yell, it should be easy to revert to a lazy
behaviour if really needed.

Reviewed By: jberdine

Differential Revision: D3304792

fbshipit-source-id: 1ddde6d
master
Jules Villard 9 years ago committed by Facebook Github Bot 8
parent 9748a8f1a3
commit 21367b0e98

@ -297,6 +297,14 @@ let mk_symbol_seq ?(default=[]) ~symbols ?(deprecated=[]) ~long ?short ?exes ?(m
String.concat "," (YBU.convert_each YBU.to_string json)]) String.concat "," (YBU.convert_each YBU.to_string json)])
~mk_spec:(fun set -> Arg.String set) ~mk_spec:(fun set -> Arg.String set)
let mk_set_from_json ~default ~default_to_string ~f
?(deprecated=[]) ~long ?short ?exes ?(meta="json") doc =
mk ~deprecated ~long ?short ?exes ~meta doc
~default ~default_to_string
~mk_setter:(fun var json -> var := f (Yojson.Basic.from_string json))
~decode_json:(fun json -> [dashdash long; Yojson.Basic.to_string json])
~mk_spec:(fun set -> Arg.String set)
let anon_fun = ref (fun arg -> raise (Arg.Bad ("unexpected anonymous argument: " ^ arg))) let anon_fun = ref (fun arg -> raise (Arg.Bad ("unexpected anonymous argument: " ^ arg)))
let mk_anon () = let mk_anon () =

@ -85,6 +85,9 @@ val mk_symbol_opt : symbols:(string * 'a) list -> 'a option ref t
element of [symbols]. *) element of [symbols]. *)
val mk_symbol_seq : ?default:'a list -> symbols:(string * 'a) list -> 'a list ref t val mk_symbol_seq : ?default:'a list -> symbols:(string * 'a) list -> 'a list ref t
val mk_set_from_json : default:'a -> default_to_string:('a -> string)
-> f:(Yojson.Basic.json -> 'a) -> 'a ref t
(** [mk_anon ()] defines a [string list ref] of the anonymous command line arguments, in the reverse (** [mk_anon ()] defines a [string list ref] of the anonymous command line arguments, in the reverse
order they appeared on the command line. *) order they appeared on the command line. *)
val mk_anon : val mk_anon :

@ -19,6 +19,16 @@ module F = Format
type language = Clang | Java type language = Clang | Java
type method_pattern = {
class_name : string;
method_name : string option;
parameters : (string list) option;
}
type pattern =
| Method_pattern of language * method_pattern
| Source_contains of language * string
let string_of_language = function let string_of_language = function
| Java -> "Java" | Java -> "Java"
| Clang -> "C_CPP" | Clang -> "C_CPP"
@ -198,6 +208,104 @@ let os_type = match Sys.os_type with
| "Cygwin" -> Cygwin | "Cygwin" -> Cygwin
| _ -> Unix | _ -> Unix
let patterns_of_json_with_key json_key json =
let default_method_pattern = {
class_name = "";
method_name = None;
parameters = None
} in
let default_source_contains = "" in
let language_of_string json_key = function
| "Java" ->
Ok Java
| l ->
Error ("Inferconfig JSON key " ^ json_key ^ " not supported for language " ^ l) in
let detect_language json_key assoc =
let rec loop = function
| [] ->
Error ("No language found for " ^ json_key ^ " in " ^ inferconfig_file)
| ("language", `String s) :: _ ->
language_of_string json_key s
| _:: tl -> loop tl in
loop assoc in
(* Detect the kind of pattern, method pattern or pattern based on the content of the source file.
Detecting the kind of patterns in a first step makes it easier to parse the parts of the
pattern in a second step *)
let detect_pattern json_key assoc =
match detect_language json_key assoc with
| Ok language ->
let is_method_pattern key = IList.exists (string_equal key) ["class"; "method"]
and is_source_contains key = IList.exists (string_equal key) ["source_contains"] in
let rec loop = function
| [] ->
Error ("Unknown pattern for " ^ json_key ^ " in " ^ inferconfig_file)
| (key, _) :: _ when is_method_pattern key ->
Ok (Method_pattern (language, default_method_pattern))
| (key, _) :: _ when is_source_contains key ->
Ok (Source_contains (language, default_source_contains))
| _:: tl -> loop tl in
loop assoc
| Error _ as error ->
error in
(* Translate a JSON entry into a matching pattern *)
let create_pattern json_key (assoc : (string * Yojson.Basic.json) list) =
let collect_params l =
let collect accu = function
| `String s -> s:: accu
| _ -> failwith ("Unrecognised parameters in " ^ Yojson.Basic.to_string (`Assoc assoc)) in
IList.rev (IList.fold_left collect [] l) in
let create_method_pattern assoc =
let loop mp = function
| (key, `String s) when key = "class" ->
{ mp with class_name = s }
| (key, `String s) when key = "method" ->
{ mp with method_name = Some s }
| (key, `List l) when key = "parameters" ->
{ mp with parameters = Some (collect_params l) }
| (key, _) when key = "language" -> mp
| _ -> failwith ("Fails to parse " ^ Yojson.Basic.to_string (`Assoc assoc)) in
IList.fold_left loop default_method_pattern assoc
and create_string_contains assoc =
let loop sc = function
| (key, `String pattern) when key = "source_contains" -> pattern
| (key, _) when key = "language" -> sc
| _ -> failwith ("Fails to parse " ^ Yojson.Basic.to_string (`Assoc assoc)) in
IList.fold_left loop default_source_contains assoc in
match detect_pattern json_key assoc with
| Ok (Method_pattern (language, _)) ->
Ok (Method_pattern (language, create_method_pattern assoc))
| Ok (Source_contains (language, _)) ->
Ok (Source_contains (language, create_string_contains assoc))
| Error _ as error ->
error in
let warn_user key msg =
F.eprintf "WARNING: in file %s: error parsing option %s@\n%s" inferconfig_file json_key msg in
(* Translate all the JSON entries into matching patterns *)
let rec translate json_key accu = function
| `Assoc l -> (
match create_pattern json_key l with
| Ok pattern ->
pattern :: accu
| Error msg ->
warn_user json_key msg;
accu)
| `List l ->
IList.fold_left (translate json_key) accu l
| json ->
warn_user json_key
(Printf.sprintf "expected list or assoc json type, but got value %s"
(Yojson.Basic.to_string json));
accu in
translate json_key [] json
(** Command Line options *) (** Command Line options *)
@ -819,6 +927,23 @@ and zip_specs_library =
~exes:CLOpt.[A] ~meta:"zip file" "add a zip file containing library spec files" ~exes:CLOpt.[A] ~meta:"zip file" "add a zip file containing library spec files"
and (
patterns_never_returning_null,
patterns_skip_translation,
patterns_modeled_expensive) =
let mk_option ~deprecated ~long doc =
CLOpt.mk_set_from_json ~deprecated ~long ~default:[] ~default_to_string:(fun _ -> "[]")
~exes:CLOpt.[J]
~f:(patterns_of_json_with_key long) doc in
(
mk_option ~deprecated:["never_returning_null"] ~long:"never-returning-null"
"Matcher or list of matchers for functions that never return `null`.",
mk_option ~deprecated:["skip_translation"] ~long:"skip-translation"
"Matcher or list of matchers for names of files that should be analyzed at all.",
mk_option ~deprecated:["modeled_expensive"] ~long:"modeled-expensive"
("Matcher or list of matchers for methods that should be considered expensive " ^
"by the performance critical checker."))
(** Global variables *) (** Global variables *)
let set_reference_and_call_function reference value f x = let set_reference_and_call_function reference value f x =
@ -1077,6 +1202,9 @@ and objc_memory_model_on = !objc_memory_model
and only_footprint = !only_footprint and only_footprint = !only_footprint
and optimistic_cast = !optimistic_cast and optimistic_cast = !optimistic_cast
and out_file_cmdline = !out_file and out_file_cmdline = !out_file
and patterns_never_returning_null = !patterns_never_returning_null
and patterns_skip_translation = !patterns_skip_translation
and patterns_modeled_expensive = !patterns_modeled_expensive
and precondition_stats = !precondition_stats and precondition_stats = !precondition_stats
and print_builtins = !print_builtins and print_builtins = !print_builtins
and print_types = !print_types and print_types = !print_types
@ -1144,4 +1272,14 @@ and suppress_warnings_json = lazy (
| Ok json -> json | Ok json -> json
| Error msg -> error ("Could not read or parse the supplied " ^ path ^ ":\n" ^ msg)) | Error msg -> error ("Could not read or parse the supplied " ^ path ^ ":\n" ^ msg))
| None -> | None ->
error ("Error: The option " ^ suppress_warnings_annotations_long ^ " was not provided")) if CLOpt.(current_exe <> J) then `Null
else error ("Error: The option " ^ suppress_warnings_annotations_long ^ " was not provided"))
let patterns_suppress_warnings =
let json_key = "suppress_warnings" in
match Lazy.force suppress_warnings_json with
| `Null -> []
| json ->
match Yojson.Basic.Util.member json_key json with
| `Null -> []
| json -> patterns_of_json_with_key json_key json

@ -18,6 +18,16 @@ type language = Clang | Java
val string_of_language : language -> string val string_of_language : language -> string
type method_pattern = {
class_name : string;
method_name : string option;
parameters : (string list) option;
}
type pattern =
| Method_pattern of language * method_pattern
| Source_contains of language * string
type clang_lang = C | CPP | OBJC | OBJCPP type clang_lang = C | CPP | OBJC | OBJCPP
type os_type = Unix | Win32 | Cygwin type os_type = Unix | Win32 | Cygwin
@ -64,6 +74,10 @@ val cpp_models_dir : string
val nsnotification_center_checker_backend : bool val nsnotification_center_checker_backend : bool
val objc_method_call_semantics : bool val objc_method_call_semantics : bool
val os_type : os_type val os_type : os_type
val patterns_never_returning_null : pattern list
val patterns_suppress_warnings : pattern list
val patterns_skip_translation : pattern list
val patterns_modeled_expensive : pattern list
val perf_stats_prefix : string val perf_stats_prefix : string
val proc_stats_filename : string val proc_stats_filename : string
val property_attributes : string val property_attributes : string

@ -52,101 +52,6 @@ let is_matching patterns =
patterns patterns
type method_pattern = {
class_name : string;
method_name : string option;
parameters : (string list) option
}
let default_method_pattern = {
class_name = "";
method_name = None;
parameters = None
}
let default_source_contains = ""
type pattern =
| Method_pattern of Config.language * method_pattern
| Source_contains of Config.language * string
let language_of_string json_key = function
| "Java" -> Config.Java
| l -> failwith ("Inferconfig JSON key " ^ json_key ^ " not supported for language " ^ l)
let detect_language json_key assoc =
let rec loop = function
| [] ->
failwith
("No language found for " ^ json_key ^ " in " ^ Config.inferconfig_file)
| (key, `String s) :: _ when key = "language" ->
language_of_string json_key s
| _:: tl -> loop tl in
loop assoc
(* Detect the kind of pattern, method pattern or pattern based on the content of the source file.
Detecting the kind of patterns in a first step makes it easier to parse the parts of the
pattern in a second step *)
let detect_pattern json_key assoc =
let language = detect_language json_key assoc in
let is_method_pattern key = IList.exists (string_equal key) ["class"; "method"]
and is_source_contains key = IList.exists (string_equal key) ["source_contains"] in
let rec loop = function
| [] ->
failwith ("Unknown pattern for " ^ json_key ^ " in " ^ Config.inferconfig_file)
| (key, _) :: _ when is_method_pattern key ->
Method_pattern (language, default_method_pattern)
| (key, _) :: _ when is_source_contains key ->
Source_contains (language, default_source_contains)
| _:: tl -> loop tl in
loop assoc
(* Translate a JSON entry into a matching pattern *)
let create_pattern json_key (assoc : (string * Yojson.Basic.json) list) =
let collect_params l =
let collect accu = function
| `String s -> s:: accu
| _ -> failwith ("Unrecognised parameters in " ^ Yojson.Basic.to_string (`Assoc assoc)) in
IList.rev (IList.fold_left collect [] l) in
let create_method_pattern assoc =
let loop mp = function
| (key, `String s) when key = "class" ->
{ mp with class_name = s }
| (key, `String s) when key = "method" ->
{ mp with method_name = Some s }
| (key, `List l) when key = "parameters" ->
{ mp with parameters = Some (collect_params l) }
| (key, _) when key = "language" -> mp
| _ -> failwith ("Fails to parse " ^ Yojson.Basic.to_string (`Assoc assoc)) in
IList.fold_left loop default_method_pattern assoc
and create_string_contains assoc =
let loop sc = function
| (key, `String pattern) when key = "source_contains" -> pattern
| (key, _) when key = "language" -> sc
| _ -> failwith ("Fails to parse " ^ Yojson.Basic.to_string (`Assoc assoc)) in
IList.fold_left loop default_source_contains assoc in
match detect_pattern json_key assoc with
| Method_pattern (language, _) ->
Method_pattern (language, create_method_pattern assoc)
| Source_contains (language, _) ->
Source_contains (language, create_string_contains assoc)
(* Translate all the JSON entries into matching patterns *)
let rec translate json_key accu (json : Yojson.Basic.json) : pattern list =
match json with
| `Assoc l -> (create_pattern json_key l):: accu
| `List l -> IList.fold_left (translate json_key) accu l
| _ -> assert false
(* Creates a list of matching patterns for the given inferconfig file *)
let load_patterns json_key json =
let found =
Yojson.Basic.Util.filter_member
json_key
[json] in
IList.fold_left (translate json_key) [] found
(** Check if a proc name is matching the name given as string. *) (** Check if a proc name is matching the name given as string. *)
let match_method language proc_name method_name = let match_method language proc_name method_name =
not (Builtin.is_registered proc_name) && not (Builtin.is_registered proc_name) &&
@ -188,18 +93,8 @@ module FileContainsStringMatcher = struct
with Sys_error _ -> false with Sys_error _ -> false
end end
module type MATCHABLE_JSON = sig
val json_key : string
end
module type Matcher = sig
type matcher = DB.source_file -> Procname.t -> bool
val load_matcher : Yojson.Basic.json Lazy.t -> matcher
end
(* Module to create matcher based on source file names or class names and method names *) (* Module to create matcher based on source file names or class names and method names *)
module FileOrProcMatcher = functor (M : MATCHABLE_JSON) -> module FileOrProcMatcher = struct
struct
type matcher = DB.source_file -> Procname.t -> bool type matcher = DB.source_file -> Procname.t -> bool
@ -215,9 +110,9 @@ struct
(fun map pattern -> (fun map pattern ->
let previous = let previous =
try try
StringMap.find pattern.class_name map StringMap.find pattern.Config.class_name map
with Not_found -> [] in with Not_found -> [] in
StringMap.add pattern.class_name (pattern:: previous) map) StringMap.add pattern.Config.class_name (pattern:: previous) map)
StringMap.empty StringMap.empty
m_patterns in m_patterns in
let do_java pname_java = let do_java pname_java =
@ -227,7 +122,7 @@ struct
let class_patterns = StringMap.find class_name pattern_map in let class_patterns = StringMap.find class_name pattern_map in
IList.exists IList.exists
(fun p -> (fun p ->
match p.method_name with match p.Config.method_name with
| None -> true | None -> true
| Some m -> string_equal m method_name) | Some m -> string_equal m method_name)
class_patterns class_patterns
@ -243,8 +138,8 @@ struct
let create_file_matcher patterns = let create_file_matcher patterns =
let s_patterns, m_patterns = let s_patterns, m_patterns =
let collect (s_patterns, m_patterns) = function let collect (s_patterns, m_patterns) = function
| Source_contains (_, s) -> (s:: s_patterns, m_patterns) | Config.Source_contains (_, s) -> (s:: s_patterns, m_patterns)
| Method_pattern (_, mp) -> (s_patterns, mp :: m_patterns) in | Config.Method_pattern (_, mp) -> (s_patterns, mp :: m_patterns) in
IList.fold_left collect ([], []) patterns in IList.fold_left collect ([], []) patterns in
let s_matcher = let s_matcher =
let matcher = FileContainsStringMatcher.create_matcher s_patterns in let matcher = FileContainsStringMatcher.create_matcher s_patterns in
@ -253,8 +148,7 @@ struct
fun source_file proc_name -> fun source_file proc_name ->
m_matcher source_file proc_name || s_matcher source_file proc_name m_matcher source_file proc_name || s_matcher source_file proc_name
let load_matcher json = let load_matcher = create_file_matcher
create_file_matcher (load_patterns M.json_key (Lazy.force json))
let _pp_pattern fmt pattern = let _pp_pattern fmt pattern =
let pp_string fmt s = let pp_string fmt s =
@ -269,54 +163,39 @@ struct
Format.fprintf fmt "[%a]" Format.fprintf fmt "[%a]"
(pp_semicolon_seq_oneline pe_text pp_string) l in (pp_semicolon_seq_oneline pe_text pp_string) l in
Format.fprintf fmt "%a%a%a" Format.fprintf fmt "%a%a%a"
(pp_key_value pp_string) ("class", Some mp.class_name) (pp_key_value pp_string) ("class", Some mp.Config.class_name)
(pp_key_value pp_string) ("method", mp.method_name) (pp_key_value pp_string) ("method", mp.Config.method_name)
(pp_key_value pp_params) ("parameters", mp.parameters) (pp_key_value pp_params) ("parameters", mp.Config.parameters)
and pp_source_contains fmt sc = and pp_source_contains fmt sc =
Format.fprintf fmt " pattern: %s\n" sc in Format.fprintf fmt " pattern: %s\n" sc in
match pattern with match pattern with
| Method_pattern (language, mp) -> | Config.Method_pattern (language, mp) ->
Format.fprintf fmt "Method pattern (%s) {\n%a}\n" Format.fprintf fmt "Method pattern (%s) {\n%a}\n"
(Config.string_of_language language) pp_method_pattern mp (Config.string_of_language language) pp_method_pattern mp
| Source_contains (language, sc) -> | Config.Source_contains (language, sc) ->
Format.fprintf fmt "Source contains (%s) {\n%a}\n" Format.fprintf fmt "Source contains (%s) {\n%a}\n"
(Config.string_of_language language) pp_source_contains sc (Config.string_of_language language) pp_source_contains sc
end (* of module FileOrProcMatcher *) end (* of module FileOrProcMatcher *)
(* Module to create patterns that will match all overriding methods in the pattern *) (* Module to create patterns that will match all overriding methods in the pattern *)
module OverridesMatcher = functor (M : MATCHABLE_JSON) -> module OverridesMatcher = struct
struct
type matcher = (string -> bool) -> Procname.t -> bool
let load_matcher json = let load_matcher patterns =
let patterns = load_patterns M.json_key (Lazy.force json) in
fun is_subtype proc_name -> fun is_subtype proc_name ->
let is_matching = function let is_matching = function
| Method_pattern (language, mp) -> | Config.Method_pattern (language, mp) ->
is_subtype mp.class_name is_subtype mp.Config.class_name
&& Option.map_default (match_method language proc_name) false mp.method_name && Option.map_default (match_method language proc_name) false mp.Config.method_name
| _ -> failwith "Expecting method pattern" in | _ -> failwith "Expecting method pattern" in
IList.exists is_matching patterns IList.exists is_matching patterns
end end
module NeverReturnNull = FileOrProcMatcher(struct let never_return_null_matcher = FileOrProcMatcher.load_matcher Config.patterns_never_returning_null
let json_key = "never_returning_null" let skip_translation_matcher = FileOrProcMatcher.load_matcher Config.patterns_skip_translation
end) let suppress_warnings_matcher = FileOrProcMatcher.load_matcher Config.patterns_suppress_warnings
let modeled_expensive_matcher = OverridesMatcher.load_matcher Config.patterns_modeled_expensive
module SuppressWarningsMatcher = FileOrProcMatcher(struct
let json_key = "suppress_warnings"
end)
module SkipTranslationMatcher = FileOrProcMatcher(struct
let json_key = "skip_translation"
end)
module ModeledExpensiveMatcher = OverridesMatcher(struct
let json_key = "modeled_expensive"
end)
let load_filters analyzer = let load_filters analyzer =
{ {

@ -31,21 +31,10 @@ val do_not_filter : filters
(** Create filters based on the config file *) (** Create filters based on the config file *)
val create_filters : analyzer -> filters val create_filters : analyzer -> filters
module type Matcher = sig val never_return_null_matcher : DB.source_file -> Procname.t -> bool
type matcher = DB.source_file -> Procname.t -> bool val suppress_warnings_matcher : DB.source_file -> Procname.t -> bool
val load_matcher : Yojson.Basic.json Lazy.t -> matcher val skip_translation_matcher : DB.source_file -> Procname.t -> bool
end val modeled_expensive_matcher : (string -> bool) -> Procname.t -> bool
module NeverReturnNull : Matcher
module SkipTranslationMatcher : Matcher
module SuppressWarningsMatcher : Matcher
module ModeledExpensiveMatcher : sig
type matcher = (string -> bool) -> Procname.t -> bool
val load_matcher : Yojson.Basic.json Lazy.t -> matcher
end
(** Load the config file and list the files to report on *) (** Load the config file and list the files to report on *)
val test: unit -> unit val test: unit -> unit

@ -110,17 +110,15 @@ let expensive_overrides_unexpensive =
let annotation_reachability_error = "CHECKERS_ANNOTATION_REACHABILITY_ERROR" let annotation_reachability_error = "CHECKERS_ANNOTATION_REACHABILITY_ERROR"
let is_modeled_expensive = let is_modeled_expensive tenv = function
let matcher = | Procname.Java proc_name_java as proc_name ->
lazy (Inferconfig.ModeledExpensiveMatcher.load_matcher Config.inferconfig_json) in not (Builtin.is_registered proc_name) &&
fun tenv proc_name -> match proc_name with let is_subclass =
| Procname.Java proc_name_java -> let classname = Typename.Java.from_string (Procname.java_get_class_name proc_name_java) in
not (Builtin.is_registered proc_name) && PatternMatch.is_subtype_of_str tenv classname in
let classname = Inferconfig.modeled_expensive_matcher is_subclass proc_name
Typename.Java.from_string (Procname.java_get_class_name proc_name_java) in | _ ->
(Lazy.force matcher) (PatternMatch.is_subtype_of_str tenv classname) proc_name false
| _ ->
false
let is_allocator tenv pname = let is_allocator tenv pname =
match pname with match pname with

@ -14,12 +14,7 @@ open Javalib_pack
let is_suppress_warnings_annotated = let is_suppress_warnings_annotated =
let matcher = lazy ( Inferconfig.suppress_warnings_matcher DB.source_file_empty
Inferconfig.SuppressWarningsMatcher.load_matcher Config.suppress_warnings_json
DB.source_file_empty) in
fun proc_name ->
(Lazy.force matcher) proc_name
let suppress_warnings = let suppress_warnings =
({ Sil.class_name = Annotations.suppress_warnings; ({ Sil.class_name = Annotations.suppress_warnings;

@ -42,10 +42,9 @@ type t =
meth_kind : meth_kind; meth_kind : meth_kind;
node : JCode.jcode Javalib.interface_or_class; node : JCode.jcode Javalib.interface_or_class;
program : JClasspath.program; program : JClasspath.program;
never_null_matcher: Inferconfig.NeverReturnNull.matcher;
} }
let create_context never_null_matcher icfg procdesc impl cn meth_kind node program = let create_context icfg procdesc impl cn meth_kind node program =
{ icfg = icfg; { icfg = icfg;
procdesc = procdesc; procdesc = procdesc;
impl = impl; impl = impl;
@ -56,7 +55,6 @@ let create_context never_null_matcher icfg procdesc impl cn meth_kind node progr
meth_kind = meth_kind; meth_kind = meth_kind;
node = node; node = node;
program = program; program = program;
never_null_matcher = never_null_matcher;
} }
let get_icfg context = context.icfg let get_icfg context = context.icfg
@ -71,7 +69,6 @@ let get_impl context = context.impl
let get_var_map context = context.var_map let get_var_map context = context.var_map
let set_var_map context var_map = context.var_map <- var_map let set_var_map context var_map = context.var_map <- var_map
let get_meth_kind context = context.meth_kind let get_meth_kind context = context.meth_kind
let get_never_null_matcher context = context.never_null_matcher
let get_or_set_pvar_type context var typ = let get_or_set_pvar_type context var typ =
let var_map = get_var_map context in let var_map = get_var_map context in

@ -45,7 +45,6 @@ type t
(** cretes a context for a given method. *) (** cretes a context for a given method. *)
val create_context : val create_context :
Inferconfig.NeverReturnNull.matcher ->
icfg -> icfg ->
Cfg.Procdesc.t -> Cfg.Procdesc.t ->
JBir.t -> JBir.t ->
@ -103,10 +102,6 @@ val get_program : t -> JClasspath.program
(** returns the current node *) (** returns the current node *)
val get_node : t -> JCode.jcode Javalib.interface_or_class val get_node : t -> JCode.jcode Javalib.interface_or_class
(** returns a match function for procedures that are never returning null
according to .inferfonfig *)
val get_never_null_matcher : t -> Inferconfig.NeverReturnNull.matcher
(** [set_pvar context var type] adds a variable with a type to the context *) (** [set_pvar context var type] adds a variable with a type to the context *)
val set_pvar : t -> JBir.var -> Sil.typ -> Pvar.t val set_pvar : t -> JBir.var -> Sil.typ -> Pvar.t

@ -73,7 +73,7 @@ let add_edges context start_node exn_node exit_nodes method_body_nodes impl supe
Array.iteri connect_nodes method_body_nodes Array.iteri connect_nodes method_body_nodes
(** Add a concrete method. *) (** Add a concrete method. *)
let add_cmethod never_null_matcher program icfg node cm is_static = let add_cmethod program icfg node cm is_static =
let cfg = icfg.JContext.cfg in let cfg = icfg.JContext.cfg in
let tenv = icfg.JContext.tenv in let tenv = icfg.JContext.tenv in
let cn, ms = JBasics.cms_split cm.Javalib.cm_class_method_signature in let cn, ms = JBasics.cms_split cm.Javalib.cm_class_method_signature in
@ -101,8 +101,7 @@ let add_cmethod never_null_matcher program icfg node cm is_static =
(instrs, JContext.Init) (instrs, JContext.Init)
else (JBir.code impl), JContext.Normal in else (JBir.code impl), JContext.Normal in
let context = let context =
JContext.create_context JContext.create_context icfg procdesc impl cn meth_kind node program in
never_null_matcher icfg procdesc impl cn meth_kind node program in
let method_body_nodes = Array.mapi (JTrans.instruction context) instrs in let method_body_nodes = Array.mapi (JTrans.instruction context) instrs in
let procname = Cfg.Procdesc.get_proc_name procdesc in let procname = Cfg.Procdesc.get_proc_name procdesc in
add_edges context start_node exn_node [exit_node] method_body_nodes impl false; add_edges context start_node exn_node [exit_node] method_body_nodes impl false;
@ -158,7 +157,7 @@ let is_classname_cached cn =
(* Given a source file and a class, translates the code of this class. (* Given a source file and a class, translates the code of this class.
In init - mode, finds out whether this class contains initializers at all, In init - mode, finds out whether this class contains initializers at all,
in this case translates it. In standard mode, all methods are translated *) in this case translates it. In standard mode, all methods are translated *)
let create_icfg never_null_matcher linereader program icfg cn node = let create_icfg linereader program icfg cn node =
JUtils.log "\tclassname: %s@." (JBasics.cn_name cn); JUtils.log "\tclassname: %s@." (JBasics.cn_name cn);
cache_classname cn; cache_classname cn;
let cfg = icfg.JContext.cfg in let cfg = icfg.JContext.cfg in
@ -171,7 +170,7 @@ let create_icfg never_null_matcher linereader program icfg cn node =
let method_kind = JTransType.get_method_kind m in let method_kind = JTransType.get_method_kind m in
match m with match m with
| Javalib.ConcreteMethod cm -> | Javalib.ConcreteMethod cm ->
add_cmethod never_null_matcher program icfg node cm method_kind add_cmethod program icfg node cm method_kind
| Javalib.AbstractMethod am -> | Javalib.AbstractMethod am ->
add_amethod program icfg am method_kind add_amethod program icfg am method_kind
) node ) node
@ -213,7 +212,7 @@ let should_capture classes package_opt source_basename node =
In the standard - mode, it translated all the classes that correspond to this In the standard - mode, it translated all the classes that correspond to this
source file. *) source file. *)
let compute_source_icfg let compute_source_icfg
never_null_matcher linereader classes program tenv linereader classes program tenv
source_basename package_opt = source_basename package_opt =
let icfg = let icfg =
{ JContext.cg = Cg.create (); { JContext.cg = Cg.create ();
@ -230,19 +229,18 @@ let compute_source_icfg
JBasics.ClassMap.iter JBasics.ClassMap.iter
(select (select
(should_capture classes package_opt source_basename) (should_capture classes package_opt source_basename)
(create_icfg never_null_matcher linereader program icfg)) (create_icfg linereader program icfg))
(JClasspath.get_classmap program) in (JClasspath.get_classmap program) in
(icfg.JContext.cg, icfg.JContext.cfg) (icfg.JContext.cg, icfg.JContext.cfg)
let compute_class_icfg never_null_matcher linereader program tenv node = let compute_class_icfg linereader program tenv node =
let icfg = let icfg =
{ JContext.cg = Cg.create (); { JContext.cg = Cg.create ();
JContext.cfg = Cfg.Node.create_cfg (); JContext.cfg = Cfg.Node.create_cfg ();
JContext.tenv = tenv } in JContext.tenv = tenv } in
begin begin
try try
create_icfg create_icfg linereader program icfg (Javalib.get_name node) node
never_null_matcher linereader program icfg (Javalib.get_name node) node
with with
| Bir.Subroutine -> () | Bir.Subroutine -> ()
| e -> raise e | e -> raise e

@ -23,7 +23,6 @@ val is_classname_cached : JBasics.class_name -> bool
(** [compute_icfg linereader classes program tenv source_basename source_file] create the call graph and control flow graph for the file [source_file] by translating all the classes in [program] originating from [source_file] *) (** [compute_icfg linereader classes program tenv source_basename source_file] create the call graph and control flow graph for the file [source_file] by translating all the classes in [program] originating from [source_file] *)
val compute_source_icfg : val compute_source_icfg :
Inferconfig.NeverReturnNull.matcher ->
Printer.LineReader.t -> Printer.LineReader.t ->
JBasics.ClassSet.t -> JBasics.ClassSet.t ->
JClasspath.program -> JClasspath.program ->
@ -34,7 +33,6 @@ val compute_source_icfg :
(** Compute the CFG for a class *) (** Compute the CFG for a class *)
val compute_class_icfg : val compute_class_icfg :
Inferconfig.NeverReturnNull.matcher ->
Printer.LineReader.t -> Printer.LineReader.t ->
JClasspath.program -> JClasspath.program ->
Tenv.t -> Tenv.t ->

@ -65,18 +65,18 @@ let store_icfg tenv cg cfg program =
(* Given a source file, its code is translated, and the call-graph, control-flow-graph and type *) (* Given a source file, its code is translated, and the call-graph, control-flow-graph and type *)
(* environment are obtained and saved. *) (* environment are obtained and saved. *)
let do_source_file let do_source_file
never_null_matcher linereader classes program tenv linereader classes program tenv
source_basename (package_opt, source_file) = source_basename (package_opt, source_file) =
JUtils.log "\nfilename: %s (%s)@." JUtils.log "\nfilename: %s (%s)@."
(DB.source_file_to_string source_file) source_basename; (DB.source_file_to_string source_file) source_basename;
let call_graph, cfg = let call_graph, cfg =
JFrontend.compute_source_icfg JFrontend.compute_source_icfg
never_null_matcher linereader classes program tenv linereader classes program tenv
source_basename package_opt in source_basename package_opt in
store_icfg tenv call_graph cfg program store_icfg tenv call_graph cfg program
let capture_libs never_null_matcher linereader program tenv = let capture_libs linereader program tenv =
let capture_class tenv cn node = let capture_class tenv cn node =
match node with match node with
| Javalib.JInterface _ -> () | Javalib.JInterface _ -> ()
@ -87,7 +87,7 @@ let capture_libs never_null_matcher linereader program tenv =
JClasspath.java_source_file_from_path (JFrontend.path_of_cached_classname cn) in JClasspath.java_source_file_from_path (JFrontend.path_of_cached_classname cn) in
init_global_state fake_source_file; init_global_state fake_source_file;
let call_graph, cfg = let call_graph, cfg =
JFrontend.compute_class_icfg never_null_matcher linereader program tenv node in JFrontend.compute_class_icfg linereader program tenv node in
store_icfg tenv call_graph cfg program; store_icfg tenv call_graph cfg program;
JFrontend.cache_classname cn; JFrontend.cache_classname cn;
end in end in
@ -135,16 +135,11 @@ let do_all_files classpath sources classes =
let program = JClasspath.load_program classpath classes in let program = JClasspath.load_program classpath classes in
let tenv = load_tenv () in let tenv = load_tenv () in
let linereader = Printer.LineReader.create () in let linereader = Printer.LineReader.create () in
let skip_translation_matcher = let skip source_file = Inferconfig.skip_translation_matcher source_file Procname.empty_block in
Inferconfig.SkipTranslationMatcher.load_matcher Config.inferconfig_json in
let never_null_matcher = Inferconfig.NeverReturnNull.load_matcher Config.inferconfig_json in
let skip source_file =
skip_translation_matcher source_file Procname.empty_block in
let translate_source_file basename (package_opt, _) source_file = let translate_source_file basename (package_opt, _) source_file =
init_global_state source_file; init_global_state source_file;
if not (skip source_file) then if not (skip source_file) then
do_source_file do_source_file linereader classes program tenv basename (package_opt, source_file) in
never_null_matcher linereader classes program tenv basename (package_opt, source_file) in
StringMap.iter StringMap.iter
(fun basename file_entry -> (fun basename file_entry ->
match file_entry with match file_entry with
@ -157,7 +152,7 @@ let do_all_files classpath sources classes =
source_files) source_files)
sources; sources;
if Config.dependency_mode then if Config.dependency_mode then
capture_libs never_null_matcher linereader program tenv; capture_libs linereader program tenv;
save_tenv tenv; save_tenv tenv;
JClasspath.cleanup program; JClasspath.cleanup program;
JUtils.log "done @." JUtils.log "done @."

@ -784,7 +784,7 @@ let rec instruction context pc instr : translation =
let ret_var = Pvar.get_ret_pvar proc_name in let ret_var = Pvar.get_ret_pvar proc_name in
let ret_type = Cfg.Procdesc.get_ret_type (JContext.get_procdesc context) in let ret_type = Cfg.Procdesc.get_ret_type (JContext.get_procdesc context) in
let loc = get_location (JContext.get_impl context) pc meth_kind cn in let loc = get_location (JContext.get_impl context) pc meth_kind cn in
let match_never_null = JContext.get_never_null_matcher context in let match_never_null = Inferconfig.never_return_null_matcher in
let create_node node_kind sil_instrs = let create_node node_kind sil_instrs =
Cfg.Node.create Cfg.Node.create
cfg cfg

Loading…
Cancel
Save