diff --git a/infer/src/IR/Tenv.re b/infer/src/IR/Tenv.re index 7b8afa5f9..86ff0c67d 100644 --- a/infer/src/IR/Tenv.re +++ b/infer/src/IR/Tenv.re @@ -48,6 +48,7 @@ let mk_struct methods::methods=? supers::supers=? annots::annots=? + specialization::specialization=? name => { let struct_typ = Typ.Struct.internal_mk_struct @@ -57,6 +58,7 @@ let mk_struct methods::?methods supers::?supers annots::?annots + specialization::?specialization (); TypenameHash.replace tenv name struct_typ; struct_typ diff --git a/infer/src/IR/Tenv.rei b/infer/src/IR/Tenv.rei index f8980d427..1d76b0bd4 100644 --- a/infer/src/IR/Tenv.rei +++ b/infer/src/IR/Tenv.rei @@ -46,6 +46,7 @@ let mk_struct: methods::list Procname.t? => supers::list Typename.t? => annots::Annot.Item.t? => + specialization::Typ.template_spec_info? => Typename.t => Typ.Struct.t; diff --git a/infer/src/IR/Typ.re b/infer/src/IR/Typ.re index e4283b6e6..d2a4de6e2 100644 --- a/infer/src/IR/Typ.re +++ b/infer/src/IR/Typ.re @@ -296,7 +296,13 @@ let java_proc_return_typ pname_java => | typ => typ }; -type typ = t; +type typ = t [@@deriving compare]; + +/* template instantiation arguments */ +type template_spec_info = + | NoTemplate + | Template (string, list (option t)) +[@@deriving compare]; let module Struct = { type field = (Ident.fieldname, T.t, Annot.Item.t) [@@deriving compare]; @@ -308,7 +314,8 @@ let module Struct = { statics: fields, /** static fields */ supers: list Typename.t, /** superclasses */ methods: list Procname.t, /** methods defined */ - annots: Annot.Item.t /** annotations */ + annots: Annot.Item.t, /** annotations */ + specialization: template_spec_info /** template specialization */ }; type lookup = Typename.t => option t; let pp pe name f {fields, supers, methods, annots} => @@ -342,21 +349,31 @@ let module Struct = { methods::methods=? supers::supers=? annots::annots=? + specialization::specialization=? () => { let mk_struct_ default:: - default={fields: [], statics: [], methods: [], supers: [], annots: Annot.Item.empty} + default={ + fields: [], + statics: [], + methods: [], + supers: [], + annots: Annot.Item.empty, + specialization: NoTemplate + } fields::fields=default.fields statics::statics=default.statics methods::methods=default.methods supers::supers=default.supers annots::annots=default.annots + specialization::specialization=default.specialization () => { fields, statics, methods, supers, - annots + annots, + specialization }; mk_struct_ default::?default @@ -365,6 +382,7 @@ let module Struct = { methods::?methods supers::?supers annots::?annots + specialization::?specialization () }; diff --git a/infer/src/IR/Typ.rei b/infer/src/IR/Typ.rei index 54baaa2d9..77542cad0 100644 --- a/infer/src/IR/Typ.rei +++ b/infer/src/IR/Typ.rei @@ -154,6 +154,12 @@ let java_proc_return_typ: Procname.java => t; type typ = t; +/* template instantiation arguments */ +type template_spec_info = + | NoTemplate + | Template (string, list (option t)) +[@@deriving compare]; + let module Struct: { type field = (Ident.fieldname, typ, Annot.Item.t) [@@deriving compare]; type fields = list field; @@ -164,7 +170,8 @@ let module Struct: { statics: fields, /** static fields */ supers: list Typename.t, /** supers */ methods: list Procname.t, /** methods defined */ - annots: Annot.Item.t /** annotations */ + annots: Annot.Item.t, /** annotations */ + specialization: template_spec_info /** template specialization */ }; type lookup = Typename.t => option t; @@ -179,6 +186,7 @@ let module Struct: { methods::list Procname.t? => supers::list Typename.t? => annots::Annot.Item.t? => + specialization::template_spec_info? => unit => t; diff --git a/infer/src/clang/CType_decl.ml b/infer/src/clang/CType_decl.ml index 10b3fe6b3..05781370e 100644 --- a/infer/src/clang/CType_decl.ml +++ b/infer/src/clang/CType_decl.ml @@ -78,6 +78,10 @@ let get_record_name_csu decl = let get_record_name decl = snd (get_record_name_csu decl) +let get_class_template_name = function + | Clang_ast_t.ClassTemplateDecl (_, name_info, _ ) -> CAst_utils.get_qualified_name name_info + | _ -> assert false + let get_superclass_decls decl = let open Clang_ast_t in match decl with @@ -164,6 +168,17 @@ and get_record_custom_type tenv definition_decl = Option.map ~f:(type_ptr_to_sil_type tenv) (get_translate_as_friend_decl decl_list) | _ -> None +and get_template_specialization tenv = function + | Clang_ast_t.ClassTemplateSpecializationDecl (_, _, _, _, _, _, _, _, spec_info) -> + let tname = match CAst_utils.get_decl spec_info.tsi_template_decl with + | Some decl -> get_class_template_name decl + | None -> assert false in + let args_in_sil = List.map spec_info.tsi_specialization_args ~f:(function + | `Type t_ptr -> Some (type_ptr_to_sil_type tenv t_ptr) + | _ -> None) in + Typ.Template (tname, args_in_sil) + | _ -> Typ.NoTemplate + and get_record_struct_type tenv definition_decl = let open Clang_ast_t in match definition_decl with @@ -190,7 +205,9 @@ and get_record_struct_type tenv definition_decl = let statics = [] in (* Note: We treat static field same as global variables *) let methods = [] in (* C++ methods are not put into tenv (info isn't used) *) let supers = get_superclass_list_cpp definition_decl in - ignore (Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots sil_typename); + let specialization = get_template_specialization tenv definition_decl in + Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots ~specialization + sil_typename |> ignore; let sil_type = Typ.Tstruct sil_typename in CAst_utils.update_sil_types_map type_ptr sil_type; sil_type