diff --git a/infer/src/IR/Tenv.ml b/infer/src/IR/Tenv.ml index a911b5718..740ea5bac 100644 --- a/infer/src/IR/Tenv.ml +++ b/infer/src/IR/Tenv.ml @@ -39,10 +39,11 @@ let lookup tenv name : Struct.t option = with Caml.Not_found -> ( (* ToDo: remove the following additional lookups once C/C++ interop is resolved *) match (name : Typ.Name.t) with - | CStruct m -> ( - try Some (TypenameHash.find tenv (CppClass (m, NoTemplate))) with Caml.Not_found -> None ) - | CppClass (m, NoTemplate) -> ( - try Some (TypenameHash.find tenv (CStruct m)) with Caml.Not_found -> None ) + | CStruct m -> + TypenameHash.find_opt tenv + (CppClass {name= m; template_spec_info= NoTemplate; is_union= false}) + | CppClass {name= m; template_spec_info= NoTemplate} -> + TypenameHash.find_opt tenv (CStruct m) | _ -> None ) diff --git a/infer/src/IR/Typ.ml b/infer/src/IR/Typ.ml index 01b2d0b4b..07fe89509 100644 --- a/infer/src/IR/Typ.ml +++ b/infer/src/IR/Typ.ml @@ -182,7 +182,10 @@ module T = struct and name = | CStruct of QualifiedCppName.t | CUnion of QualifiedCppName.t - | CppClass of QualifiedCppName.t * template_spec_info + | CppClass of + { name: QualifiedCppName.t + ; template_spec_info: template_spec_info + ; is_union: bool [@compare.ignore] } | JavaClass of JavaClassName.t | ObjcClass of QualifiedCppName.t * name list | ObjcProtocol of QualifiedCppName.t @@ -306,8 +309,8 @@ and pp_name_c_syntax pe f = function QualifiedCppName.pp f name | ObjcClass (name, protocol_names) -> F.fprintf f "%a%a" QualifiedCppName.pp name (pp_protocols pe) protocol_names - | CppClass (name, template_spec) -> - F.fprintf f "%a%a" QualifiedCppName.pp name (pp_template_spec_info pe) template_spec + | CppClass {name; template_spec_info} -> + F.fprintf f "%a%a" QualifiedCppName.pp name (pp_template_spec_info pe) template_spec_info | JavaClass name -> JavaClassName.pp f name @@ -362,8 +365,8 @@ module Name = struct that, we can use these loosened compare functions instead. *) let loose_compare x y = match (x, y) with - | (CStruct name1 | CppClass (name1, NoTemplate)), (CStruct name2 | CppClass (name2, NoTemplate)) - -> + | ( (CStruct name1 | CppClass {name= name1; template_spec_info= NoTemplate}) + , (CStruct name2 | CppClass {name= name2; template_spec_info= NoTemplate}) ) -> QualifiedCppName.compare name1 name2 | _ -> compare x y @@ -377,8 +380,8 @@ module Name = struct | ObjcClass (name, protocol_names) -> let protocols = F.asprintf "%a" (pp_protocols Pp.text) protocol_names in QualifiedCppName.append_protocols name ~protocols - | CppClass (name, templ_args) -> - let template_suffix = F.asprintf "%a" (pp_template_spec_info Pp.text) templ_args in + | CppClass {name; template_spec_info} -> + let template_suffix = F.asprintf "%a" (pp_template_spec_info Pp.text) template_spec_info in QualifiedCppName.append_template_args_to_last name ~args:template_suffix | JavaClass _ -> QualifiedCppName.empty @@ -387,13 +390,18 @@ module Name = struct let unqualified_name = function | CStruct name | CUnion name | ObjcProtocol name | ObjcClass (name, _) -> name - | CppClass (name, _) -> + | CppClass {name} -> name | JavaClass _ -> QualifiedCppName.empty - let get_template_spec_info = function CppClass (_, templ_args) -> Some templ_args | _ -> None + let get_template_spec_info = function + | CppClass {template_spec_info} -> + Some template_spec_info + | _ -> + None + let name n = match n with @@ -479,7 +487,9 @@ module Name = struct end module Cpp = struct - let from_qual_name template_spec_info qual_name = CppClass (qual_name, template_spec_info) + let from_qual_name template_spec_info ~is_union qual_name = + CppClass {name= qual_name; template_spec_info; is_union} + let is_class = function CppClass _ -> true | _ -> false end diff --git a/infer/src/IR/Typ.mli b/infer/src/IR/Typ.mli index cbce5873e..aedb36e27 100644 --- a/infer/src/IR/Typ.mli +++ b/infer/src/IR/Typ.mli @@ -102,14 +102,13 @@ and desc = and name = | CStruct of QualifiedCppName.t | CUnion of QualifiedCppName.t - (* qualified name does NOT contain template arguments of the class. It will contain template - args of its parent classes, for example: MyClass::InnerClass will store - "MyClass", "InnerClass" *) - | CppClass of QualifiedCppName.t * template_spec_info + (** qualified name does NOT contain template arguments of the class. It will contain template + args of its parent classes, for example: MyClass::InnerClass will store + "MyClass", "InnerClass" *) + | CppClass of {name: QualifiedCppName.t; template_spec_info: template_spec_info; is_union: bool} | JavaClass of JavaClassName.t | ObjcClass of QualifiedCppName.t * name list - (* ObjC class that conforms to a list of protocols, - e.g. id *) + (** ObjC class that conforms to a list of protocols, e.g. id *) | ObjcProtocol of QualifiedCppName.t and template_arg = TType of t | TInt of Int64.t | TNull | TNullPtr | TOpaque @@ -215,7 +214,7 @@ module Name : sig end module Cpp : sig - val from_qual_name : template_spec_info -> QualifiedCppName.t -> t + val from_qual_name : template_spec_info -> is_union:bool -> QualifiedCppName.t -> t (** Create a typename from a C++ classname *) val is_class : t -> bool diff --git a/infer/src/absint/ConcurrencyModels.ml b/infer/src/absint/ConcurrencyModels.ml index 1bd92c358..e8689c514 100644 --- a/infer/src/absint/ConcurrencyModels.ml +++ b/infer/src/absint/ConcurrencyModels.ml @@ -380,8 +380,8 @@ let runs_on_ui_thread tenv pname = let is_recursive_lock_type = function - | Typ.CppClass (qname, _) -> - Clang.is_recursive_lock_type qname + | Typ.CppClass {name} -> + Clang.is_recursive_lock_type name | _ -> (* non-C++ lock types are always considered recursive *) true diff --git a/infer/src/absint/ProcnameDispatcher.ml b/infer/src/absint/ProcnameDispatcher.ml index 0a6ee95bb..264d48b10 100644 --- a/infer/src/absint/ProcnameDispatcher.ml +++ b/infer/src/absint/ProcnameDispatcher.ml @@ -48,7 +48,7 @@ let templated_name_of_class_name class_name = | ObjcClass (qual_name, protocol_names) -> let protocols = F.asprintf "%a" (Typ.pp_protocols Pp.text) protocol_names in (QualifiedCppName.append_protocols qual_name ~protocols, []) - | CppClass (qual_name, template_spec_info) -> + | CppClass {name= qual_name; template_spec_info} -> (qual_name, template_args_of_template_spec_info template_spec_info) | JavaClass mangled_name -> (QualifiedCppName.of_list [JavaClassName.to_string mangled_name], []) diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index 0fb30b44e..bba81c86c 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -279,7 +279,7 @@ let placement_new size_exp {exp= src_exp1; typ= t1} src_arg2_opt = match (t1.Typ.desc, src_arg2_opt) with | Tint _, None | Tint _, Some {typ= {Typ.desc= Tint _}} -> malloc ~can_be_zero:true (Exp.BinOp (Binop.PlusA (Some Typ.size_t), size_exp, src_exp1)) - | Tstruct (CppClass (name, _)), None + | Tstruct (CppClass {name}), None when [%compare.equal: string list] (QualifiedCppName.to_list name) ["std"; "nothrow_t"] -> malloc ~can_be_zero:true size_exp | _, _ -> @@ -668,7 +668,11 @@ end module Split = struct let std_vector model_env ~adds_at_least_one ({typ= vector_typ} as vec_arg) mem = match vector_typ with - | Typ.{desc= Tptr ({desc= Tstruct (CppClass (_, Template {args= TType elt_typ :: _}))}, _)} -> + | Typ. + { desc= + Tptr + ( {desc= Tstruct (CppClass {template_spec_info= Template {args= TType elt_typ :: _}})} + , _ ) } -> let arr_locs = StdVector.deref_of model_env elt_typ vec_arg mem in let size = if adds_at_least_one then Dom.Val.Itv.pos else Dom.Val.Itv.nat in StdVector.set_size model_env arr_locs size mem diff --git a/infer/src/clang/CType_decl.ml b/infer/src/clang/CType_decl.ml index a588187d2..4ece90ed5 100644 --- a/infer/src/clang/CType_decl.ml +++ b/infer/src/clang/CType_decl.ml @@ -299,7 +299,7 @@ let create_c_record_typename (tag_kind : Clang_ast_t.tag_kind) = | `TTK_Union -> Typ.Name.C.union_from_qual_name | `TTK_Class -> - Typ.Name.Cpp.from_qual_name Typ.NoTemplate + Typ.Name.Cpp.from_qual_name Typ.NoTemplate ~is_union:false let get_class_template_name = function @@ -449,10 +449,12 @@ and get_record_friend_decl_type tenv definition_decl = and get_record_typename ?tenv decl = let open Clang_ast_t in let linters_mode = match tenv with Some _ -> false | None -> true in + let is_union_tag tag_kind = match tag_kind with `TTK_Union -> true | _ -> false in match (decl, tenv) with | RecordDecl (_, name_info, _, _, _, tag_kind, _), _ -> CAst_utils.get_qualified_name ~linters_mode name_info |> create_c_record_typename tag_kind - | ClassTemplateSpecializationDecl (_, _, _, _, _, _, _, _, mangling, spec_info), Some tenv -> + | ClassTemplateSpecializationDecl (_, _, _, _, _, tag_kind, _, _, mangling, spec_info), Some tenv + -> let tname = match CAst_utils.get_decl spec_info.tsi_template_decl with | Some dec -> @@ -462,15 +464,17 @@ and get_record_typename ?tenv decl = in let args = get_template_args tenv spec_info in let mangled = if String.equal "" mangling then None else Some mangling in - Typ.Name.Cpp.from_qual_name (Typ.Template {mangled; args}) tname + Typ.Name.Cpp.from_qual_name + (Typ.Template {mangled; args}) + ~is_union:(is_union_tag tag_kind) tname | CXXRecordDecl (_, name_info, _, _, _, `TTK_Union, _, _), _ -> Typ.CUnion (CAst_utils.get_qualified_name ~linters_mode name_info) - | CXXRecordDecl (_, name_info, _, _, _, _, _, _), _ - | ClassTemplatePartialSpecializationDecl (_, name_info, _, _, _, _, _, _, _, _), _ - | ClassTemplateSpecializationDecl (_, name_info, _, _, _, _, _, _, _, _), _ -> + | CXXRecordDecl (_, name_info, _, _, _, tag_kind, _, _), _ + | ClassTemplatePartialSpecializationDecl (_, name_info, _, _, _, tag_kind, _, _, _, _), _ + | ClassTemplateSpecializationDecl (_, name_info, _, _, _, tag_kind, _, _, _, _), _ -> (* we use Typ.CppClass for C++ because we expect Typ.CppClass from *) (* types that have methods. And in C++ struct/class/union can have methods *) - Typ.Name.Cpp.from_qual_name Typ.NoTemplate + Typ.Name.Cpp.from_qual_name Typ.NoTemplate ~is_union:(is_union_tag tag_kind) (CAst_utils.get_qualified_name ~linters_mode name_info) | ObjCInterfaceDecl (_, name_info, _, _, _), _ | ObjCImplementationDecl (_, name_info, _, _, _), _ -> diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 96b0a54ff..afa59d411 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -586,7 +586,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s builtin_pname | None -> let class_typename = - Typ.Name.Cpp.from_qual_name Typ.NoTemplate + Typ.Name.Cpp.from_qual_name Typ.NoTemplate ~is_union:false (CAst_utils.get_class_name_from_member name_info) in if is_inner_destructor then @@ -3791,7 +3791,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (Exp.Sizeof {typ; nbytes= None; dynamic_length= None; subtype= Subtype.exact}, void_typ) in let class_tname = - Typ.Name.Cpp.from_qual_name Typ.NoTemplate (QualifiedCppName.of_list ["std"; "type_info"]) + Typ.Name.Cpp.from_qual_name Typ.NoTemplate ~is_union:false + (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