diff --git a/infer/src/IR/QualifiedCppName.re b/infer/src/IR/QualifiedCppName.re index d9b9edacf..da9acc0a8 100644 --- a/infer/src/IR/QualifiedCppName.re +++ b/infer/src/IR/QualifiedCppName.re @@ -8,30 +8,42 @@ */ open! IStd; +/* internally it uses reversed list to store qualified name, for example: ["get", "shared_ptr", "std"]*/ type t = list string [@@deriving compare]; let equal = [%compare.equal : t]; let empty = []; -let append_qualifier quals qual::qual => List.append quals [qual]; +let append_qualifier quals qual::qual => List.cons qual quals; -let to_list quals => quals; +let extract_last = + fun + | [last, ...rest] => Some (last, rest) + | [] => None; -let of_list quals => quals; +let to_list = List.rev; + +let to_rev_list = ident; + +let of_list = List.rev; + +let of_rev_list = ident; let cpp_separator = "::"; /* This is simplistic and will give the wrong answer in some cases, eg "foo>::someMethod" will get parsed as ["foo>", "someMethod"]. Avoid using it if possible */ -let of_qual_string = { +let of_qual_string str => { let class_sep_regex = Str.regexp_string cpp_separator; /* wait until here to define the function so that [class_sep_regex] is only computed once */ - Str.split class_sep_regex + Str.split class_sep_regex str |> List.rev }; -let to_qual_string = String.concat sep::cpp_separator; +let to_separated_string quals sep::sep => List.rev quals |> String.concat sep::sep; + +let to_qual_string = to_separated_string sep::cpp_separator; let pp fmt quals => Format.fprintf fmt "%s" (to_qual_string quals); @@ -39,7 +51,7 @@ let module Match = { type quals_matcher = Str.regexp; let matching_separator = "#"; let regexp_string_of_qualifiers quals => - Str.quote (String.concat sep::matching_separator quals) ^ "$"; + Str.quote (to_separated_string sep::matching_separator quals) ^ "$"; let qualifiers_list_matcher quals_list => ( if (List.is_empty quals_list) { @@ -66,6 +78,6 @@ let module Match = { let no_template_name s => List.hd_exn (String.split on::'<' s); List.map f::no_template_name quals }; - Str.string_match matcher (String.concat sep::matching_separator normalized_qualifiers) 0 + Str.string_match matcher (to_separated_string sep::matching_separator normalized_qualifiers) 0 }; }; diff --git a/infer/src/IR/QualifiedCppName.rei b/infer/src/IR/QualifiedCppName.rei index a2160bc71..428102995 100644 --- a/infer/src/IR/QualifiedCppName.rei +++ b/infer/src/IR/QualifiedCppName.rei @@ -29,13 +29,25 @@ let to_qual_string: t => string; let append_qualifier: t => qual::string => t; +/** returns last (innermost scope) qualifier and qualified name without last qualifier */ +let extract_last: t => option (string, t); + + /** returns list of qualifers */ let to_list: t => list string; +/** returns reversed list of qualifiers, ie innermost scope is the first element */ +let to_rev_list: t => list string; + + /** given list of qualifiers in normal order produce qualified name ["std", "move"] */ let of_list: list string => t; + +/** given reversed list of qualifiers, produce qualified name (ie. ["move", "std"] for std::move )*/ +let of_rev_list: list string => t; + let pp: Format.formatter => t => unit; /* Module to match qualified C++ procnames "fuzzily", that is up to namescapes and templating. In diff --git a/infer/src/IR/Typ.re b/infer/src/IR/Typ.re index 548e5ccee..16678b02d 100644 --- a/infer/src/IR/Typ.re +++ b/infer/src/IR/Typ.re @@ -911,7 +911,7 @@ let module Procname = { let to_filename pname => { /* filenames for clang procs are REVERSED qualifiers with '#' as separator */ let get_qual_name_str pname => - get_qualifiers pname |> QualifiedCppName.to_list |> List.rev |> String.concat sep::"#"; + get_qualifiers pname |> QualifiedCppName.to_rev_list |> String.concat sep::"#"; let proc_id = switch pname { | C {mangled} => diff --git a/infer/src/clang/cAst_utils.ml b/infer/src/clang/cAst_utils.ml index c0056bacc..fb625a1f7 100644 --- a/infer/src/clang/cAst_utils.ml +++ b/infer/src/clang/cAst_utils.ml @@ -19,7 +19,7 @@ type type_ptr_to_sil_type = Tenv.t -> Clang_ast_t.type_ptr -> Typ.t let sanitize_name = Str.global_replace (Str.regexp "[/ ]") "_" let get_qual_name qual_name_list = - List.rev_map ~f:sanitize_name qual_name_list |> QualifiedCppName.of_list + List.map ~f:sanitize_name qual_name_list |> QualifiedCppName.of_rev_list let get_qualified_name name_info = get_qual_name name_info.Clang_ast_t.ni_qual_name diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index da74a6ecf..fe3fcc1f4 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -139,16 +139,14 @@ struct QualifiedCppName.Match.of_fuzzy_qual_names Config.whitelisted_cpp_methods in let class_matcher = QualifiedCppName.Match.of_fuzzy_qual_names Config.whitelisted_cpp_classes in - fun qual_method_rev -> + fun qual_name -> (* either the method is explictely whitelisted, or the whole class is whitelisted *) - QualifiedCppName.Match.match_qualifiers method_matcher - (List.rev qual_method_rev |> QualifiedCppName.of_list) || - match qual_method_rev with - | _::(_::_ as class_name_rev) -> + QualifiedCppName.Match.match_qualifiers method_matcher qual_name || + match QualifiedCppName.extract_last qual_name with + | Some (_, class_qual_name) -> (* make sure the class name is not empty; in particular, it cannot be a C function *) - QualifiedCppName.Match.match_qualifiers class_matcher - (List.rev class_name_rev |> QualifiedCppName.of_list) - | _ -> + QualifiedCppName.Match.match_qualifiers class_matcher class_qual_name + | None -> false let should_translate_decl trans_unit_ctx dec decl_trans_context = @@ -157,7 +155,7 @@ struct let translate_when_used = match dec with | Clang_ast_t.FunctionDecl (_, name_info, _, _) | Clang_ast_t.CXXMethodDecl (_, name_info, _, _, _) -> - is_whitelisted_cpp_method name_info.Clang_ast_t.ni_qual_name + is_whitelisted_cpp_method (CAst_utils.get_qualified_name name_info) | _ -> false in let translate_location = CLocation.should_translate_lib trans_unit_ctx source_range decl_trans_context