diff --git a/facebook-clang-plugins b/facebook-clang-plugins index c7b64f085..71ada2c99 160000 --- a/facebook-clang-plugins +++ b/facebook-clang-plugins @@ -1 +1 @@ -Subproject commit c7b64f0852dd3e9eacc2c5608461909994e4f425 +Subproject commit 71ada2c9994be2af8e8915e45d1c61c9d6a53d62 diff --git a/infer/src/IR/Exceptions.ml b/infer/src/IR/Exceptions.ml index 52d323d21..cfcd556c2 100644 --- a/infer/src/IR/Exceptions.ml +++ b/infer/src/IR/Exceptions.ml @@ -235,7 +235,7 @@ let recognize_exception exn = (Localise.from_string "Match failure", Localise.no_desc, Some ml_loc, Exn_developer, High, None, Nocat) | Missing_fld (fld, ml_loc) -> - let desc = Localise.verbatim_desc (Typ.Fieldname.to_string fld) in + let desc = Localise.verbatim_desc (Typ.Fieldname.to_full_string fld) in (Localise.from_string "Missing_fld" ~hum:"Missing Field", desc, Some ml_loc, Exn_developer, Medium, None, Nocat) | Premature_nil_termination (desc, ml_loc) -> diff --git a/infer/src/IR/Typ.re b/infer/src/IR/Typ.re index e816ba2fc..4b6544f9e 100644 --- a/infer/src/IR/Typ.re +++ b/infer/src/IR/Typ.re @@ -1030,8 +1030,7 @@ let java_proc_return_typ pname_java :t => { }; module Fieldname = { - type clang_field_info = {qual_class: QualifiedCppName.t, field_name: string} - [@@deriving compare]; + type clang_field_info = {class_name: Name.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 clang_field_info @@ -1046,7 +1045,7 @@ module Fieldname = { module Set = Caml.Set.Make T; module Map = Caml.Map.Make T; module Clang = { - let from_qualified qual_class field_name => Clang {qual_class, field_name}; + let from_class_name class_name field_name => Clang {class_name, field_name}; }; module Java = { let from_string n => Java n; @@ -1071,6 +1070,11 @@ module Fieldname = { | _ => s } }; + let to_full_string fname => + switch fname { + | Clang {class_name, field_name} => Name.to_string class_name ^ "::" ^ field_name + | _ => to_string fname + }; /** Convert a fieldname to a flat string without path. */ let to_flat_string fn => { @@ -1114,7 +1118,7 @@ module Fieldname = { }; let clang_get_qual_class = fun - | Clang {qual_class} => Some qual_class + | Clang {class_name} => Some (Name.qual_name class_name) | _ => None; /** hidded fieldname constant */ diff --git a/infer/src/IR/Typ.rei b/infer/src/IR/Typ.rei index 5bd0bd58a..961b67710 100644 --- a/infer/src/IR/Typ.rei +++ b/infer/src/IR/Typ.rei @@ -490,11 +490,7 @@ module Fieldname: { /** Map for fieldnames */ module Map: Caml.Map.S with type key = t; - module Clang: { - - /** Create a clang field name from qualified c++ name */ - let from_qualified: QualifiedCppName.t => string => t; - }; + module Clang: {let from_class_name: Name.t => string => t;}; module Java: { /** Create a java field name from string */ @@ -503,6 +499,7 @@ module Fieldname: { /** Convert a field name to a string. */ let to_string: t => string; + let to_full_string: t => string; /** Convert a fieldname to a simplified string with at most one-level path. */ let to_simplified_string: t => string; diff --git a/infer/src/clang/CType_decl.ml b/infer/src/clang/CType_decl.ml index 96e644916..7751e8921 100644 --- a/infer/src/clang/CType_decl.ml +++ b/infer/src/clang/CType_decl.ml @@ -90,9 +90,10 @@ let rec get_struct_fields tenv decl = | CXXRecordDecl (_, _, _, _, decl_list, _, _, _) | RecordDecl (_, _, _, _, decl_list, _, _) -> decl_list | _ -> [] in + let class_tname = get_record_typename ~tenv decl in let do_one_decl decl = match decl with - | FieldDecl (_, name_info, qt, _) -> - let id = CGeneral_utils.mk_class_field_name name_info in + | FieldDecl (_, {ni_name}, qt, _) -> + let id = CGeneral_utils.mk_class_field_name class_tname ni_name in let typ = qual_type_to_sil_type tenv qt in let annotation_items = [] in (* For the moment we don't use them*) [(id, typ, annotation_items)] @@ -140,10 +141,14 @@ and get_record_typename ?tenv decl = | ObjCInterfaceDecl (_, name_info, _, _, _), _ | ObjCImplementationDecl (_, name_info, _, _, _), _ - | ObjCProtocolDecl (_, name_info, _, _, _), _ - | ObjCCategoryDecl (_, name_info, _, _, _), _ - | ObjCCategoryImplDecl (_, name_info, _, _, _), _ -> + | ObjCProtocolDecl (_, name_info, _, _, _), _ -> CAst_utils.get_qualified_name name_info |> Typ.Name.Objc.from_qual_name + | ObjCCategoryDecl (_, _, _, _, {odi_class_interface=Some {dr_name}}), _ + | ObjCCategoryImplDecl (_, _, _, _, {ocidi_class_interface=Some {dr_name}}), _ -> ( + match dr_name with + | Some name_info -> + CAst_utils.get_qualified_name name_info |> Typ.Name.Objc.from_qual_name + | None -> assert false) | _ -> assert false (** fetches list of superclasses for C++ classes *) diff --git a/infer/src/clang/cField_decl.ml b/infer/src/clang/cField_decl.ml index 1faf36445..ae2daa145 100644 --- a/infer/src/clang/cField_decl.ml +++ b/infer/src/clang/cField_decl.ml @@ -35,14 +35,14 @@ let fields_superclass tenv interface_decl_info = | _ -> []) | _ -> [] -let build_sil_field qual_type_to_sil_type tenv field_name qual_type prop_attributes = +let build_sil_field qual_type_to_sil_type tenv class_tname field_name qual_type prop_attributes = let prop_atts = List.map ~f:Clang_ast_j.string_of_property_attribute prop_attributes in let annotation_from_type t = match t.Typ.desc with | Typ.Tptr (_, Typ.Pk_objc_weak) -> [Config.weak] | Typ.Tptr (_, Typ.Pk_objc_unsafe_unretained) -> [Config.unsafe_unret] | _ -> [] in - let fname = CGeneral_utils.mk_class_field_name field_name in + let fname = CGeneral_utils.mk_class_field_name class_tname field_name.Clang_ast_t.ni_name in let typ = qual_type_to_sil_type tenv qual_type in let item_annotations = match prop_atts with | [] -> @@ -55,11 +55,11 @@ let build_sil_field qual_type_to_sil_type tenv field_name qual_type prop_attribu fname, typ, item_annotations (* Given a list of declarations in an interface returns a list of fields *) -let rec get_fields qual_type_to_sil_type tenv decl_list = +let rec get_fields qual_type_to_sil_type tenv class_tname decl_list = let open Clang_ast_t in let add_field name_info (qt : qual_type) attributes decl_list' = - let fields = get_fields qual_type_to_sil_type tenv decl_list' in - let field_tuple = build_sil_field qual_type_to_sil_type tenv + let fields = get_fields qual_type_to_sil_type tenv class_tname decl_list' in + let field_tuple = build_sil_field qual_type_to_sil_type tenv class_tname name_info qt attributes in CGeneral_utils.append_no_duplicates_fields [field_tuple] fields in match decl_list with @@ -70,11 +70,11 @@ let rec get_fields qual_type_to_sil_type tenv decl_list = | Some (ObjCIvarDecl (_, name_info, qual_type, _, _)) -> let attributes = obj_c_property_decl_info.Clang_ast_t.opdi_property_attributes in add_field name_info qual_type attributes decl_list' - | _ -> get_fields qual_type_to_sil_type tenv decl_list') + | _ -> get_fields qual_type_to_sil_type tenv class_tname decl_list') | ObjCIvarDecl (_, name_info, qual_type, _, _) :: decl_list' -> add_field name_info qual_type [] decl_list' | _ :: decl_list' -> - get_fields qual_type_to_sil_type tenv decl_list' + get_fields qual_type_to_sil_type tenv class_tname decl_list' (* Add potential extra fields defined only in the implementation of the class *) (* to the info given in the interface. Update the tenv accordingly. *) @@ -95,9 +95,8 @@ let modelled_fields_in_classes = let modelled_field class_name_info = let modelled_field_in_class res (class_name, field_name, typ) = if String.equal class_name class_name_info.Clang_ast_t.ni_name then - let class_name_qualified = class_name_info.Clang_ast_t.ni_qual_name in - let field_name_qualified = CAst_utils.make_qual_name_decl class_name_qualified field_name in - let name = CGeneral_utils.mk_class_field_name field_name_qualified in + let class_tname = Typ.Name.Objc.from_string class_name in + let name = Typ.Fieldname.Clang.from_class_name class_tname field_name in (name, typ, Annot.Item.empty) :: res else res in List.fold ~f:modelled_field_in_class ~init:[] modelled_fields_in_classes diff --git a/infer/src/clang/cField_decl.mli b/infer/src/clang/cField_decl.mli index 9fab86c79..4bfefc4b8 100644 --- a/infer/src/clang/cField_decl.mli +++ b/infer/src/clang/cField_decl.mli @@ -13,8 +13,8 @@ open! IStd type field_type = Typ.Fieldname.t * Typ.t * (Annot.t * bool) list -val get_fields : CAst_utils.qual_type_to_sil_type -> Tenv.t -> Clang_ast_t.decl list -> - field_type list +val get_fields : CAst_utils.qual_type_to_sil_type -> Tenv.t -> Typ.Name.t -> + Clang_ast_t.decl list -> field_type list val fields_superclass : Tenv.t -> Clang_ast_t.obj_c_interface_decl_info -> field_type list diff --git a/infer/src/clang/cGeneral_utils.ml b/infer/src/clang/cGeneral_utils.ml index a5b070479..cd01e1045 100644 --- a/infer/src/clang/cGeneral_utils.ml +++ b/infer/src/clang/cGeneral_utils.ml @@ -99,10 +99,8 @@ let list_range i j = 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 - Typ.Fieldname.Clang.from_qualified class_name field_name +let mk_class_field_name class_tname field_name = + Typ.Fieldname.Clang.from_class_name class_tname field_name let is_cpp_translation translation_unit_context = let lang = translation_unit_context.CFrontend_config.lang in diff --git a/infer/src/clang/cGeneral_utils.mli b/infer/src/clang/cGeneral_utils.mli index aec465182..cf9b8e2f1 100644 --- a/infer/src/clang/cGeneral_utils.mli +++ b/infer/src/clang/cGeneral_utils.mli @@ -43,7 +43,7 @@ val list_range: int -> int -> int list val replicate: int -> 'a -> 'a list -val mk_class_field_name : Clang_ast_t.named_decl_info -> Typ.Fieldname.t +val mk_class_field_name : Typ.Name.t -> string -> Typ.Fieldname.t val get_var_name_mangled : Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> (string * Mangled.t) diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 5a8bfe3d7..c2e8a0c82 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -371,8 +371,13 @@ let get_objc_property_accessor ms = | Some (ObjCPropertyDecl (_, _, obj_c_property_decl_info)) -> let ivar_decl_ref = obj_c_property_decl_info.Clang_ast_t.opdi_ivar_decl in (match CAst_utils.get_decl_opt_with_decl_ref ivar_decl_ref with - | Some ObjCIvarDecl (_, named_decl_info, _, _, _) -> - let field_name = CGeneral_utils.mk_class_field_name named_decl_info in + | Some ObjCIvarDecl (_ , {ni_name}, _, _, _) -> + let class_tname = match CMethod_signature.ms_get_name ms with + | Typ.Procname.ObjC_Cpp objc_cpp -> + Typ.Procname.objc_cpp_get_class_type_name objc_cpp + | _ -> assert false + in + let field_name = CGeneral_utils.mk_class_field_name class_tname ni_name in if CMethod_signature.ms_is_getter ms then Some (ProcAttributes.Objc_getter field_name) else if CMethod_signature.ms_is_setter ms then diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index bd3b0e04c..fb07e3bbc 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -108,8 +108,8 @@ struct let procname = Procdesc.get_proc_name procdesc in let mk_field_from_captured_var (var, typ) = let vname = Pvar.get_name var in - let qual_name = CAst_utils.make_qual_name_decl [block_name] (Mangled.to_string vname) in - let fname = CGeneral_utils.mk_class_field_name qual_name in + let tname = Typ.Name.C.from_string block_name in + let fname = CGeneral_utils.mk_class_field_name tname (Mangled.to_string vname) in let item_annot = Annot.Item.empty in fname, typ, item_annot in let fields = List.map ~f:mk_field_from_captured_var captured_vars in @@ -494,8 +494,9 @@ struct let open CContext in let context = trans_state.context in let sil_loc = CLocation.get_sil_location stmt_info context in - let name_info, _, qual_type = CAst_utils.get_info_from_decl_ref decl_ref in - L.(debug Capture Verbose) "!!!!! Dealing with field '%s' @." name_info.Clang_ast_t.ni_name; + let name_info, decl_ptr, qual_type = CAst_utils.get_info_from_decl_ref decl_ref in + let field_string = name_info.Clang_ast_t.ni_name in + L.(debug Capture Verbose) "!!!!! Dealing with field '%s' @." field_string; let field_typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in let (obj_sil, class_typ) = extract_exp_from_list pre_trans_result.exps "WARNING: in Field dereference we expect to know the object@\n" in @@ -507,7 +508,16 @@ struct | Typ.Tptr (t, _) -> t | _ -> class_typ in L.(debug Capture Verbose) "Type is '%s' @." (Typ.to_string class_typ); - let field_name = CGeneral_utils.mk_class_field_name name_info in + let class_tname = match CAst_utils.get_decl decl_ptr with + | Some FieldDecl ({di_parent_pointer}, _, _, _) + | Some ObjCIvarDecl ({di_parent_pointer}, _, _, _, _) -> ( + match CAst_utils.get_decl_opt di_parent_pointer with + | Some decl -> CType_decl.get_record_typename ~tenv:context.tenv decl + | _ -> assert false + ) + | _ -> assert false (* di_parent_pointer should be always set for fields/ivars *) + in + let field_name = CGeneral_utils.mk_class_field_name class_tname field_string in let field_exp = Exp.Lfield (obj_sil, field_name, class_typ) in (* In certain cases, there is be no LValueToRValue cast, but backend needs dereference*) (* there either way:*) @@ -2343,8 +2353,9 @@ struct let void_typ = Typ.mk Tvoid in let type_info_objc = (Exp.Sizeof {typ; nbytes=None; dynamic_length=None; subtype=Subtype.exact}, void_typ) in - let field_name_decl = CAst_utils.make_qual_name_decl ["type_info"; "std"] "__type_name" in - let field_name = CGeneral_utils.mk_class_field_name field_name_decl in + let class_tname = + Typ.Name.Cpp.from_qual_name Typ.NoTemplate (QualifiedCppName.of_list ["std"; "type_info"]) in + let field_name = CGeneral_utils.mk_class_field_name class_tname "__type_name" in let ret_exp = Exp.Var ret_id in let field_exp = Exp.Lfield (ret_exp, field_name, typ) in let args = type_info_objc :: (field_exp, void_typ) :: res_trans_subexpr.exps in diff --git a/infer/src/clang/objcCategory_decl.ml b/infer/src/clang/objcCategory_decl.ml index c0080c4ee..48496676b 100644 --- a/infer/src/clang/objcCategory_decl.ml +++ b/infer/src/clang/objcCategory_decl.ml @@ -66,8 +66,8 @@ let get_base_class_name_from_category decl = (* Add potential extra fields defined only in the category *) (* to the corresponding class. Update the tenv accordingly.*) let process_category qual_type_to_sil_type tenv class_name decl_info decl_list = - let decl_fields = CField_decl.get_fields qual_type_to_sil_type tenv decl_list in let class_tn_name = Typ.Name.Objc.from_qual_name class_name in + let decl_fields = CField_decl.get_fields qual_type_to_sil_type tenv class_tn_name decl_list in let class_tn_desc = Typ.Tstruct class_tn_name in let decl_key = Clang_ast_extend.DeclPtr decl_info.Clang_ast_t.di_pointer in CAst_utils.update_sil_types_map decl_key class_tn_desc; diff --git a/infer/src/clang/objcInterface_decl.ml b/infer/src/clang/objcInterface_decl.ml index e743bca5e..b69509b1b 100644 --- a/infer/src/clang/objcInterface_decl.ml +++ b/infer/src/clang/objcInterface_decl.ml @@ -65,12 +65,12 @@ let get_interface_supers super_opt protocols = let super_classes = super_class@protocol_names in super_classes -let create_supers_fields qual_type_to_sil_type tenv decl_list +let create_supers_fields qual_type_to_sil_type tenv class_tname decl_list otdi_super otdi_protocols = let super = get_super_interface_decl otdi_super in let protocols = get_protocols otdi_protocols in let supers = get_interface_supers super protocols in - let fields = CField_decl.get_fields qual_type_to_sil_type tenv decl_list in + let fields = CField_decl.get_fields qual_type_to_sil_type tenv class_tname decl_list in supers, fields (* Adds pairs (interface name, interface_type_info) to the global environment. *) @@ -82,7 +82,7 @@ let add_class_to_tenv qual_type_to_sil_type tenv decl_info name_info decl_list o let decl_key = Clang_ast_extend.DeclPtr decl_info.Clang_ast_t.di_pointer in CAst_utils.update_sil_types_map decl_key interface_desc; let decl_supers, decl_fields = - create_supers_fields qual_type_to_sil_type tenv decl_list + create_supers_fields qual_type_to_sil_type tenv interface_name decl_list ocidi.Clang_ast_t.otdi_super ocidi.Clang_ast_t.otdi_protocols in let fields_sc = CField_decl.fields_superclass tenv ocidi in @@ -140,9 +140,9 @@ let interface_impl_declaration qual_type_to_sil_type tenv decl = L.(debug Capture Verbose) "ADDING: ObjCImplementationDecl for class '%a'@\n" QualifiedCppName.pp class_name; let _ = add_class_decl qual_type_to_sil_type tenv idi in - let fields = CField_decl.get_fields qual_type_to_sil_type tenv decl_list in - CField_decl.add_missing_fields tenv class_name fields; let class_tn_name = Typ.Name.Objc.from_qual_name class_name in + let fields = CField_decl.get_fields qual_type_to_sil_type tenv class_tn_name decl_list in + CField_decl.add_missing_fields tenv class_name fields; let decl_key = Clang_ast_extend.DeclPtr decl_info.Clang_ast_t.di_pointer in let class_desc = Typ.Tstruct class_tn_name in CAst_utils.update_sil_types_map decl_key class_desc;