@ -52,101 +52,6 @@ let is_matching 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. *)
let match_method language proc_name method_name =
not ( Builtin . is_registered proc_name ) &&
@ -188,18 +93,8 @@ module FileContainsStringMatcher = struct
with Sys_error _ -> false
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 FileOrProcMatcher = functor ( M : MATCHABLE_JSON ) ->
struct
module FileOrProcMatcher = struct
type matcher = DB . source_file -> Procname . t -> bool
@ -215,9 +110,9 @@ struct
( fun map pattern ->
let previous =
try
StringMap . find pattern . class_name map
StringMap . find pattern . Config . class_name map
with Not_found -> [] in
StringMap . add pattern . class_name ( pattern :: previous ) map )
StringMap . add pattern . Config . class_name ( pattern :: previous ) map )
StringMap . empty
m_patterns in
let do_java pname_java =
@ -227,7 +122,7 @@ struct
let class_patterns = StringMap . find class_name pattern_map in
IList . exists
( fun p ->
match p . method_name with
match p . Config . method_name with
| None -> true
| Some m -> string_equal m method_name )
class_patterns
@ -243,8 +138,8 @@ struct
let create_file_matcher patterns =
let s_patterns , m_patterns =
let collect ( s_patterns , m_patterns ) = function
| Source_contains ( _ , s ) -> ( s :: s_patterns , m_patterns )
| Method_pattern ( _ , mp ) -> ( s_patterns , mp :: m_patterns ) in
| Config . Source_contains ( _ , s ) -> ( s :: s_patterns , m_patterns )
| Config . Method_pattern ( _ , mp ) -> ( s_patterns , mp :: m_patterns ) in
IList . fold_left collect ( [] , [] ) patterns in
let s_matcher =
let matcher = FileContainsStringMatcher . create_matcher s_patterns in
@ -253,8 +148,7 @@ struct
fun source_file proc_name ->
m_matcher source_file proc_name | | s_matcher source_file proc_name
let load_matcher json =
create_file_matcher ( load_patterns M . json_key ( Lazy . force json ) )
let load_matcher = create_file_matcher
let _ pp_pattern fmt pattern =
let pp_string fmt s =
@ -269,54 +163,39 @@ struct
Format . fprintf fmt " [%a] "
( pp_semicolon_seq_oneline pe_text pp_string ) l in
Format . fprintf fmt " %a%a%a "
( pp_key_value pp_string ) ( " class " , Some mp . class_name )
( pp_key_value pp_string ) ( " method " , mp . method_name )
( pp_key_value pp_params ) ( " parameters " , mp . parameters )
( pp_key_value pp_string ) ( " class " , Some mp . Config . class_name )
( pp_key_value pp_string ) ( " method " , mp . Config . method_name )
( pp_key_value pp_params ) ( " parameters " , mp . Config . parameters )
and pp_source_contains fmt sc =
Format . fprintf fmt " pattern: %s \n " sc in
match pattern with
| Method_pattern ( language , mp ) ->
| Config . Method_pattern ( language , mp ) ->
Format . fprintf fmt " Method pattern (%s) { \n %a} \n "
( 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 "
( Config . string_of_language language ) pp_source_contains sc
end (* of module FileOrProcMatcher *)
(* Module to create patterns that will match all overriding methods in the pattern *)
module OverridesMatcher = functor ( M : MATCHABLE_JSON ) ->
struct
type matcher = ( string -> bool ) -> Procname . t -> bool
module OverridesMatcher = struct
let load_matcher json =
let patterns = load_patterns M . json_key ( Lazy . force json ) in
let load_matcher patterns =
fun is_subtype proc_name ->
let is_matching = function
| Method_pattern ( language , mp ) ->
is_subtype mp . class_name
&& Option . map_default ( match_method language proc_name ) false mp . method_name
| Config . Method_pattern ( language , mp ) ->
is_subtype mp . Config . class_name
&& Option . map_default ( match_method language proc_name ) false mp . Config . method_name
| _ -> failwith " Expecting method pattern " in
IList . exists is_matching patterns
end
module NeverReturnNull = FileOrProcMatcher ( struct
let json_key = " never_returning_null "
end )
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 never_return_null_matcher = FileOrProcMatcher . load_matcher Config . patterns_never_returning_null
let skip_translation_matcher = FileOrProcMatcher . load_matcher Config . patterns_skip_translation
let suppress_warnings_matcher = FileOrProcMatcher . load_matcher Config . patterns_suppress_warnings
let modeled_expensive_matcher = OverridesMatcher . load_matcher Config . patterns_modeled_expensive
let load_filters analyzer =
{