diff --git a/infer/src/IR/Fieldname.re b/infer/src/IR/Fieldname.re index 6a9b18a98..f5a327d6f 100644 --- a/infer/src/IR/Fieldname.re +++ b/infer/src/IR/Fieldname.re @@ -10,9 +10,11 @@ open! IStd; let module Hashtbl = Caml.Hashtbl; +type clang_field_info = {qual_class: QualifiedCppName.t, field_name: string} [@@deriving compare]; + type t = | Hidden /* Backend relies that Hidden is the smallest (first) field in Abs.should_raise_objc_leak */ - | Clang Mangled.t + | Clang clang_field_info | Java string [@@deriving compare]; @@ -31,14 +33,10 @@ let module Map = Caml.Map.Make { }; let module Clang = { - - /** Create a field name with the given position (field number in the CSU) */ - let create (n: Mangled.t) => Clang n; + let from_qualified qual_class field_name => Clang {qual_class, field_name}; }; let module Java = { - - /** Create a field name with the given position (field number in the CSU) */ let from_string n => Java n; }; @@ -48,15 +46,7 @@ let to_string = fun | Hidden => hidden_str | Java fname => fname - | Clang fname => Mangled.to_string fname; - - -/** Convert a fieldname to a string, including the mangled part. */ -let to_complete_string = - fun - | Hidden => hidden_str - | Java fname => fname - | Clang fname => Mangled.to_string_full fname; + | Clang {field_name} => field_name; /** Convert a fieldname to a simplified string with at most one-level path. */ @@ -85,8 +75,8 @@ let to_flat_string fn => { let pp f => fun | Hidden => Format.fprintf f "%s" hidden_str - | Java fname => Format.fprintf f "%s" fname - | Clang fname => Mangled.pp f fname; + | Java field_name + | Clang {field_name} => Format.fprintf f "%s" field_name; let pp_latex style f fn => Latex.pp_string style f (to_string fn); @@ -119,6 +109,11 @@ let java_is_outer_instance fn => { } }; +let clang_get_qual_class = + fun + | Clang {qual_class} => Some qual_class + | _ => None; + /** hidded fieldname constant */ let hidden = Hidden; diff --git a/infer/src/IR/Fieldname.rei b/infer/src/IR/Fieldname.rei index 07d24f0c1..32b68f8be 100644 --- a/infer/src/IR/Fieldname.rei +++ b/infer/src/IR/Fieldname.rei @@ -26,13 +26,13 @@ let module Map: Caml.Map.S with type key = t; let module Clang: { - /** Create a clang field name */ - let create: Mangled.t => t; + /** Create a clang field name from qualified c++ name */ + let from_qualified: QualifiedCppName.t => string => t; }; let module Java: { - /** Create a java field name */ + /** Create a java field name from string */ let from_string: string => t; }; @@ -41,10 +41,6 @@ let module Java: { let to_string: t => string; -/** Convert a fieldname to a string, including the mangled part. */ -let to_complete_string: t => string; - - /** Convert a fieldname to a simplified string with at most one-level path. */ let to_simplified_string: t => string; @@ -73,6 +69,10 @@ let java_get_field: t => string; let java_is_outer_instance: t => bool; +/** get qualified classname of a field if it's coming from clang frontend. returns None otherwise */ +let clang_get_qual_class: t => option QualifiedCppName.t; + + /** hidded fieldname constant */ let hidden: t; diff --git a/infer/src/IR/QualifiedCppName.re b/infer/src/IR/QualifiedCppName.re index 56c4ea771..f9257511e 100644 --- a/infer/src/IR/QualifiedCppName.re +++ b/infer/src/IR/QualifiedCppName.re @@ -8,7 +8,9 @@ */ open! IStd; -type t = list string; +type t = list string [@@deriving compare]; + +let equal = [%compare.equal : t]; let empty = []; diff --git a/infer/src/IR/QualifiedCppName.rei b/infer/src/IR/QualifiedCppName.rei index 8f9cfc2b4..e21f53979 100644 --- a/infer/src/IR/QualifiedCppName.rei +++ b/infer/src/IR/QualifiedCppName.rei @@ -8,12 +8,13 @@ */ open! IStd; -type t; +type t [@@deriving compare]; /** empty qualified name */ let empty: t; +let equal: t => t => bool; /** attempts to parse the argument into a list::of::possibly::templated<T>::qualifiers */ let of_qual_string: string => t; @@ -26,7 +27,6 @@ let to_qual_string: t => string; /** append qualifier to the end (innermost scope) of the qualified name */ let append_qualifier: t => qual::string => t; - /** returns list of qualifers */ let to_list: t => list string; diff --git a/infer/src/IR/Typ.re b/infer/src/IR/Typ.re index abc10816b..d343d7351 100644 --- a/infer/src/IR/Typ.re +++ b/infer/src/IR/Typ.re @@ -884,11 +884,14 @@ let module Procname = { /** Pretty print a set of proc names */ let pp_set fmt set => Set.iter (fun pname => F.fprintf fmt "%a " pp pname) set; + let objc_cpp_get_class_qualifiers objc_cpp => QualifiedCppName.of_qual_string ( + Name.name objc_cpp.class_name + ); let get_qualifiers pname => switch pname { | C {name} => QualifiedCppName.of_qual_string name | ObjC_Cpp objc_cpp => - QualifiedCppName.of_qual_string (Name.name objc_cpp.class_name) |> + objc_cpp_get_class_qualifiers objc_cpp |> QualifiedCppName.append_qualifier qual::objc_cpp.method_name | _ => QualifiedCppName.empty }; diff --git a/infer/src/IR/Typ.rei b/infer/src/IR/Typ.rei index be5599c8c..87e23f331 100644 --- a/infer/src/IR/Typ.rei +++ b/infer/src/IR/Typ.rei @@ -427,7 +427,12 @@ let module Procname: { /** Convert a proc name to a filename. */ let to_filename: t => string; + + /** get qualifiers of C/objc/C++ method/function */ let get_qualifiers: t => QualifiedCppName.t; + + /** get qualifiers of a class owning objc/C++ method */ + let objc_cpp_get_class_qualifiers: objc_cpp => QualifiedCppName.t; }; diff --git a/infer/src/backend/errdesc.ml b/infer/src/backend/errdesc.ml index 9e0b3ca8e..e17ef79e3 100644 --- a/infer/src/backend/errdesc.ml +++ b/infer/src/backend/errdesc.ml @@ -16,35 +16,33 @@ module L = Logging module F = Format module DExp = DecompiledExp -let mutex_class = ["std"; "mutex"] -let vector_class = ["std"; "vector"] +let vector_matcher = QualifiedCppName.Match.of_fuzzy_qual_names ["std::vector"] +let mutex_matcher = QualifiedCppName.Match.of_fuzzy_qual_names ["std::mutex"] -let is_one_of_classes class_name classes = - List.exists ~f:(fun wrapper_class -> - List.for_all ~f:(fun wrapper_class_substring -> - String.is_substring ~substring:wrapper_class_substring class_name) wrapper_class) - classes +let is_one_of_classes = QualifiedCppName.Match.match_qualifiers -let is_method_of_objc_cpp_class pname classes = + +let is_method_of_objc_cpp_class pname matcher = match pname with - | Typ.Procname.ObjC_Cpp name -> - let class_name = Typ.Procname.objc_cpp_get_class_name name in - is_one_of_classes class_name classes + | Typ.Procname.ObjC_Cpp objc_cpp -> + let class_qual_opt = Typ.Procname.objc_cpp_get_class_qualifiers objc_cpp in + is_one_of_classes matcher class_qual_opt | _ -> false let is_mutex_method pname = - is_method_of_objc_cpp_class pname [mutex_class] + is_method_of_objc_cpp_class pname mutex_matcher let is_vector_method pname = - is_method_of_objc_cpp_class pname [vector_class] + is_method_of_objc_cpp_class pname vector_matcher -let is_special_field class_names field_name_opt field = - let complete_fieldname = Fieldname.to_complete_string field in +let is_special_field matcher field_name_opt field = + let field_name = Fieldname.to_flat_string field in + let class_qual_opt = Fieldname.clang_get_qual_class field in let field_ok = match field_name_opt with - | Some field_name -> String.is_substring ~substring:field_name complete_fieldname + | Some field_name' -> String.equal field_name' field_name | None -> true in - is_one_of_classes complete_fieldname class_names && field_ok + field_ok && Option.value_map ~f:(is_one_of_classes matcher) ~default:false class_qual_opt (** Check whether the hpred is a |-> representing a resource in the Racquire state *) let hpred_is_open_resource tenv prop = function @@ -842,9 +840,9 @@ let create_dereference_desc tenv else desc | Some (DExp.Darrow (dexp, fieldname)) -> - if is_special_field [mutex_class] (Some "null_if_locked") fieldname then + if is_special_field mutex_matcher (Some "null_if_locked") fieldname then Localise.desc_double_lock None (DExp.to_string dexp) loc - else if is_special_field [vector_class] (Some "beginPtr") fieldname then + else if is_special_field vector_matcher (Some "beginPtr") fieldname then Localise.desc_empty_vector_access None (DExp.to_string dexp) loc else desc diff --git a/infer/src/clang/cGeneral_utils.ml b/infer/src/clang/cGeneral_utils.ml index 2bbe2a3e5..1e2cbe415 100644 --- a/infer/src/clang/cGeneral_utils.ml +++ b/infer/src/clang/cGeneral_utils.ml @@ -102,7 +102,8 @@ let replicate n el = List.map ~f:(fun _ -> el) (list_range 0 (n -1)) let mk_class_field_name field_qual_name = let field_name = field_qual_name.Clang_ast_t.ni_name in let class_name = CAst_utils.get_class_name_from_member field_qual_name in - Fieldname.Clang.create (Mangled.mangled field_name class_name) + let qual_class_name = QualifiedCppName.of_qual_string class_name in + Fieldname.Clang.from_qualified qual_class_name field_name let is_cpp_translation translation_unit_context = let lang = translation_unit_context.CFrontend_config.lang in