From 93789132239cfb237ec8f7ba5d1287744a287e75 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Wed, 20 Jul 2016 05:27:55 -0700 Subject: [PATCH] add constructor info to c++ methods Summary: Store more information inside Procname.objc_cpp type: replace mangling info with "kind" info, which also contains mangling info when appropriate. Reviewed By: akotulski Differential Revision: D3580283 fbshipit-source-id: b1197ed --- infer/src/IR/Procname.re | 88 +++++++++++++++++++-------- infer/src/IR/Procname.rei | 19 +++--- infer/src/backend/modelBuiltins.ml | 2 +- infer/src/backend/taint.ml | 3 +- infer/src/clang/cFrontend_checkers.ml | 2 +- infer/src/clang/cFrontend_utils.ml | 16 +++-- infer/src/clang/cFrontend_utils.mli | 5 +- infer/src/clang/cTrans_models.ml | 10 +-- infer/src/clang/cTrans_models.mli | 2 +- infer/src/clang/cTrans_utils.ml | 4 +- infer/src/clang/cTypes_decl.ml | 5 +- 11 files changed, 98 insertions(+), 58 deletions(-) diff --git a/infer/src/IR/Procname.re b/infer/src/IR/Procname.re index 2b54034d8..7fd534928 100644 --- a/infer/src/IR/Procname.re +++ b/infer/src/IR/Procname.re @@ -39,9 +39,16 @@ type java = { /** Type of c procedure names. */ type c = (string, option string); +type objc_cpp_method_kind = + | CPPMethod of (option string) /** with mangling */ + | CPPConstructor of (option string) /** with mangling */ + | ObjCInstanceMethod + | ObjCInternalMethod + | ObjCClassMethod; + /** Type of Objective C and C++ procedure names: method signatures. */ -type objc_cpp = {class_name: string, method_name: string, mangled: option string}; +type objc_cpp = {class_name: string, method_name: string, kind: objc_cpp_method_kind}; /** Type of Objective C block names. */ @@ -55,19 +62,11 @@ type t = | Java of java | C of c | ObjC_Cpp of objc_cpp | Block of block; /** Level of verbosity of some to_string functions. */ type detail_level = | Verbose | Non_verbose | Simple; -type objc_method_kind = | Instance_objc_method | Class_objc_method; - -let mangled_of_objc_method_kind kind => - switch kind { - | Instance_objc_method => Some "instance" - | Class_objc_method => Some "class" - }; - let objc_method_kind_of_bool is_instance => if is_instance { - Instance_objc_method + ObjCInstanceMethod } else { - Class_objc_method + ObjCClassMethod }; let empty_block = Block ""; @@ -156,12 +155,21 @@ let java_compare (j1: java) (j2: java) => next java_return_type_compare j1.return_type j2.return_type |> next method_kind_compare j1.kind j2.kind; -let c_function_mangled_compare mangled1 mangled2 => - switch (mangled1, mangled2) { - | (Some _, None) => 1 - | (None, Some _) => (-1) - | (None, None) => 0 - | (Some mangled1, Some mangled2) => string_compare mangled1 mangled2 +let objc_cpp_method_kind_compare k1 k2 => + switch (k1, k2) { + | (CPPMethod mangled1, CPPMethod mangled2) => mangled_compare mangled1 mangled2 + | (CPPMethod _, _) => (-1) + | (_, CPPMethod _) => 1 + | (CPPConstructor mangled1, CPPConstructor mangled2) => mangled_compare mangled1 mangled2 + | (CPPConstructor _, _) => (-1) + | (_, CPPConstructor _) => 1 + | (ObjCClassMethod, ObjCClassMethod) => 0 + | (ObjCClassMethod, _) => (-1) + | (_, ObjCClassMethod) => 1 + | (ObjCInstanceMethod, ObjCInstanceMethod) => 0 + | (ObjCInstanceMethod, _) => (-1) + | (_, ObjCInstanceMethod) => 1 + | (ObjCInternalMethod, ObjCInternalMethod) => 0 }; @@ -169,7 +177,7 @@ let c_function_mangled_compare mangled1 mangled2 => let c_meth_sig_compare osig1 osig2 => string_compare osig1.method_name osig2.method_name |> next string_compare osig1.class_name osig2.class_name |> - next c_function_mangled_compare osig1.mangled osig2.mangled; + next objc_cpp_method_kind_compare osig1.kind osig2.kind; /** Given a package.class_name string, it looks for the latest dot and split the string @@ -190,10 +198,10 @@ let java class_name return_type method_name parameters kind => { /** Create an objc procedure name from a class_name and method_name. */ -let objc_cpp class_name method_name mangled => {class_name, method_name, mangled}; +let objc_cpp class_name method_name kind => {class_name, method_name, kind}; let get_default_objc_class_method objc_class => { - let objc_cpp = objc_cpp objc_class "__find_class_" (Some "internal"); + let objc_cpp = objc_cpp objc_class "__find_class_" ObjCInternalMethod; ObjC_Cpp objc_cpp }; @@ -421,15 +429,22 @@ let java_is_vararg = } | _ => false; -let is_obj_constructor method_name => method_name == "new" || string_is_prefix "init" method_name; +let is_objc_constructor method_name => method_name == "new" || string_is_prefix "init" method_name; +let is_objc_kind = + fun + | ObjCClassMethod + | ObjCInstanceMethod + | ObjCInternalMethod => true + | _ => false; -/** [is_constructor pname] returns true if [pname] is a constructor - TODO: add case for C++ */ + +/** [is_constructor pname] returns true if [pname] is a constructor */ let is_constructor = fun | Java js => js.method_name == "" - | ObjC_Cpp name => is_obj_constructor name.method_name + | ObjC_Cpp {kind: CPPConstructor _} => true + | ObjC_Cpp {kind, method_name} when is_objc_kind kind => is_objc_constructor method_name | _ => false; let is_objc_dealloc method_name => method_name == "dealloc"; @@ -486,9 +501,28 @@ let c_method_to_string osig detail_level => | Non_verbose => osig.class_name ^ "_" ^ osig.method_name | Verbose => let m_str = - switch osig.mangled { - | None => "" - | Some s => "{" ^ s ^ "}" + switch osig.kind { + | CPPMethod m => + "(" ^ + ( + switch m { + | None => "" + | Some s => s + } + ) ^ + ")" + | CPPConstructor m => + "{" ^ + ( + switch m { + | None => "" + | Some s => s + } + ) ^ + "}" + | ObjCClassMethod => "class" + | ObjCInstanceMethod => "instance" + | ObjCInternalMethod => "internal" }; osig.class_name ^ "_" ^ osig.method_name ^ m_str }; diff --git a/infer/src/IR/Procname.rei b/infer/src/IR/Procname.rei index c84d5dda1..73c0ddc15 100644 --- a/infer/src/IR/Procname.rei +++ b/infer/src/IR/Procname.rei @@ -40,9 +40,12 @@ type method_kind = | Static /* in Java, procedures called with invokestatic */ | Non_Static /* in Java, procedures called with invokevirtual, invokespecial, and invokeinterface */; -type objc_method_kind = - | Instance_objc_method /* for instance methods in ObjC */ - | Class_objc_method /* for class methods in ObjC */; +type objc_cpp_method_kind = + | CPPMethod of (option string) /** with mangling */ + | CPPConstructor of (option string) /** with mangling */ + | ObjCInstanceMethod + | ObjCInternalMethod + | ObjCClassMethod; /** Hash tables with proc names as keys. */ @@ -98,7 +101,7 @@ let is_c_method: t => bool; /** Check if this is a constructor method in Objective-C. */ -let is_obj_constructor: string => bool; +let is_objc_constructor: string => bool; /** Check if this is a constructor. */ @@ -134,12 +137,8 @@ let java_replace_return_type: java => java_type => java; let mangled_objc_block: string => t; -/** Mangled string for method types. */ -let mangled_of_objc_method_kind: objc_method_kind => option string; - - /** Create an objc procedure name from a class_name and method_name. */ -let objc_cpp: string => string => option string => objc_cpp; +let objc_cpp: string => string => objc_cpp_method_kind => objc_cpp; let get_default_objc_class_method: string => t; @@ -149,7 +148,7 @@ let objc_cpp_get_class_name: objc_cpp => string; /** Create ObjC method type from a bool is_instance. */ -let objc_method_kind_of_bool: bool => objc_method_kind; +let objc_method_kind_of_bool: bool => objc_cpp_method_kind; /** Return the class name of a java procedure name. */ diff --git a/infer/src/backend/modelBuiltins.ml b/infer/src/backend/modelBuiltins.ml index 67bb900d9..4ec3dcfb6 100644 --- a/infer/src/backend/modelBuiltins.ml +++ b/infer/src/backend/modelBuiltins.ml @@ -1170,7 +1170,7 @@ let execute_objc_alloc_no_fail SymExec.instrs tenv pdesc [alloc_instr] symb_state let mk_objc_class_method class_name method_name = - let method_kind = Procname.mangled_of_objc_method_kind Procname.Class_objc_method in + let method_kind = Procname.ObjCClassMethod in (Procname.ObjC_Cpp (Procname.objc_cpp class_name method_name method_kind)) diff --git a/infer/src/backend/taint.ml b/infer/src/backend/taint.ml index a8e5042ad..735e9adf5 100644 --- a/infer/src/backend/taint.ml +++ b/infer/src/backend/taint.ml @@ -273,9 +273,8 @@ let java_method_to_procname java_method = (* turn string specificiation of an objc method into a procname *) let objc_method_to_procname objc_method = let method_kind = Procname.objc_method_kind_of_bool (not objc_method.is_static) in - let mangled = Procname.mangled_of_objc_method_kind method_kind in Procname.ObjC_Cpp - (Procname.objc_cpp objc_method.classname objc_method.method_name mangled) + (Procname.objc_cpp objc_method.classname objc_method.method_name method_kind) let taint_spec_to_taint_info taint_spec = let taint_source = diff --git a/infer/src/clang/cFrontend_checkers.ml b/infer/src/clang/cFrontend_checkers.ml index 2f1856a15..0b8871e91 100644 --- a/infer/src/clang/cFrontend_checkers.ml +++ b/infer/src/clang/cFrontend_checkers.ml @@ -233,7 +233,7 @@ let direct_atomic_property_access_warning method_decl stmt_info ivar_decl_ref = Last two conditions avoids false positives *) is_ivar_atomic (get_ivar_attributes d) && not (is_method_property_accessor_of_ivar method_decl ivar_pointer) - && not (Procname.is_obj_constructor method_name) + && not (Procname.is_objc_constructor method_name) && not (Procname.is_objc_dealloc method_name) in if condition then Some { diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index 4ff5746d0..1e0eccc6f 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -632,13 +632,17 @@ struct Procname.C (Procname.c name mangled) let mk_procname_from_objc_method class_name method_name method_kind = - let mangled = Procname.mangled_of_objc_method_kind method_kind in Procname.ObjC_Cpp - (Procname.objc_cpp class_name method_name mangled) - - let mk_procname_from_cpp_method class_name method_name mangled_opt = + (Procname.objc_cpp class_name method_name method_kind) + + let mk_procname_from_cpp_method class_name method_name ?meth_decl mangled = + let method_kind = match meth_decl with + | Some (Clang_ast_t.CXXConstructorDecl _) -> + Procname.CPPConstructor mangled + | _ -> + Procname.CPPMethod mangled in Procname.ObjC_Cpp - (Procname.objc_cpp class_name method_name mangled_opt) + (Procname.objc_cpp class_name method_name method_kind) let get_objc_method_name name_info mdi class_name = let method_name = name_info.Clang_ast_t.ni_name in @@ -661,7 +665,7 @@ struct let mangled = get_mangled_method_name fdi mdi in let method_name = Ast_utils.get_unqualified_name name_info in let class_name = Ast_utils.get_class_name_from_member name_info in - mk_procname_from_cpp_method class_name method_name mangled + mk_procname_from_cpp_method class_name method_name ~meth_decl mangled | ObjCMethodDecl (_, name_info, mdi) -> let class_name = Ast_utils.get_class_name_from_member name_info in get_objc_method_name name_info mdi class_name diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index eaaddc38e..dd91b142e 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -199,7 +199,7 @@ sig val replicate: int -> 'a -> 'a list - val mk_procname_from_objc_method : string -> string -> Procname.objc_method_kind -> Procname.t + val mk_procname_from_objc_method : string -> string -> Procname.objc_cpp_method_kind -> Procname.t val mk_procname_from_function : string -> (Clang_ast_t.decl_info * Clang_ast_t.function_decl_info) option -> Config.clang_lang -> Procname.t @@ -207,7 +207,8 @@ sig val get_mangled_method_name : Clang_ast_t.function_decl_info -> Clang_ast_t.cxx_method_decl_info -> string option - val mk_procname_from_cpp_method : string -> string -> string option-> Procname.t + val mk_procname_from_cpp_method : + string -> string -> ?meth_decl:Clang_ast_t.decl -> string option -> Procname.t val procname_of_decl : Clang_ast_t.decl -> Procname.t diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index 5ed568b27..b145471e8 100644 --- a/infer/src/clang/cTrans_models.ml +++ b/infer/src/clang/cTrans_models.ml @@ -145,7 +145,7 @@ let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname la && method_name = CFrontend_config.string_with_utf8_m in let id_type = Ast_expressions.create_id_type in let args = [(Mangled.from_string "x", Ast_expressions.create_char_star_type)] in - get_predefined_ms_method condition class_name method_name Procname.Class_objc_method + get_predefined_ms_method condition class_name method_name Procname.ObjCClassMethod mk_procname lang args id_type [] None let get_predefined_ms_retain_release method_name mk_procname lang = @@ -156,7 +156,7 @@ let get_predefined_ms_retain_release method_name mk_procname lang = let class_name = CFrontend_config.nsobject_cl in let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in let args = [(Mangled.from_string CFrontend_config.self, class_type)] in - get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method + get_predefined_ms_method condition class_name method_name Procname.ObjCInstanceMethod mk_procname lang args return_type [] (get_builtinname method_name) let get_predefined_ms_autoreleasepool_init class_name method_name mk_procname lang = @@ -164,7 +164,7 @@ let get_predefined_ms_autoreleasepool_init class_name method_name mk_procname la method_name = CFrontend_config.init && class_name = CFrontend_config.nsautorelease_pool_cl in let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in - get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method + get_predefined_ms_method condition class_name method_name Procname.ObjCInstanceMethod mk_procname lang [(Mangled.from_string CFrontend_config.self, class_type)] Ast_expressions.create_void_type [] None @@ -174,7 +174,7 @@ let get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procna && class_name = CFrontend_config.nsautorelease_pool_cl in let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in let args = [(Mangled.from_string CFrontend_config.self, class_type)] in - get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method + get_predefined_ms_method condition class_name method_name Procname.ObjCInstanceMethod mk_procname lang args Ast_expressions.create_void_type [] (Some ModelBuiltins.__objc_release_autorelease_pool) @@ -182,7 +182,7 @@ let get_predefined_ms_is_kind_of_class class_name method_name mk_procname lang = let condition = method_name = CFrontend_config.is_kind_of_class in let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in let args = [(Mangled.from_string CFrontend_config.self, class_type)] in - get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method + get_predefined_ms_method condition class_name method_name Procname.ObjCInstanceMethod mk_procname lang args Ast_expressions.create_BOOL_type [] (Some ModelBuiltins.__instanceof) diff --git a/infer/src/clang/cTrans_models.mli b/infer/src/clang/cTrans_models.mli index 62b55edb9..7e88646aa 100644 --- a/infer/src/clang/cTrans_models.mli +++ b/infer/src/clang/cTrans_models.mli @@ -28,7 +28,7 @@ val is_modeled_builtin : string -> bool val is_toll_free_bridging : Procname.t option -> bool val get_predefined_model_method_signature : string -> string -> - (string -> string -> Procname.objc_method_kind -> Procname.t) -> + (string -> string -> Procname.objc_cpp_method_kind -> Procname.t) -> Config.clang_lang -> CMethod_signature.method_signature option val is_dispatch_function_name : string -> (string * int) option diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 4c7ead58e..74e8ae694 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -332,7 +332,9 @@ let objc_new_trans trans_state loc stmt_info cls_name function_type = let init_ret_id = Ident.create_fresh Ident.knormal in let is_instance = true in let call_flags = { CallFlags.default with CallFlags.cf_virtual = is_instance; } in - let pname = General_utils.mk_procname_from_objc_method cls_name CFrontend_config.init Procname.Instance_objc_method in + let pname = + General_utils.mk_procname_from_objc_method + cls_name CFrontend_config.init Procname.ObjCInstanceMethod in CMethod_trans.create_external_procdesc trans_state.context.CContext.cfg pname is_instance None; let args = [(alloc_ret_exp, alloc_ret_type)] in let init_stmt_call = diff --git a/infer/src/clang/cTypes_decl.ml b/infer/src/clang/cTypes_decl.ml index 84b53cc39..79716afc2 100644 --- a/infer/src/clang/cTypes_decl.ml +++ b/infer/src/clang/cTypes_decl.ml @@ -103,7 +103,7 @@ let get_record_name_csu decl = let get_record_name decl = snd (get_record_name_csu decl) let get_class_methods class_name decl_list = - let process_method_decl = function + let process_method_decl meth_decl = match meth_decl with | Clang_ast_t.CXXMethodDecl (_, name_info, _, fdi, mdi) | Clang_ast_t.CXXConstructorDecl (_, name_info, _, fdi, mdi) | Clang_ast_t.CXXConversionDecl (_, name_info, _, fdi, mdi) @@ -111,7 +111,8 @@ let get_class_methods class_name decl_list = let method_name = name_info.Clang_ast_t.ni_name in Printing.log_out " ...Declaring method '%s'.\n" method_name; let mangled = General_utils.get_mangled_method_name fdi mdi in - let procname = General_utils.mk_procname_from_cpp_method class_name method_name mangled in + let procname = + General_utils.mk_procname_from_cpp_method class_name method_name ~meth_decl mangled in Some procname | _ -> None in (* poor mans list_filter_map *)