You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

663 lines
20 KiB

(*
* Copyright (c) 2009-2013, Monoidics ltd.
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
(** The Smallfoot Intermediate Language: Types *)
open! IStd
module F = Format
(** Kinds of integers *)
type ikind =
| IChar (** [char] *)
| ISChar (** [signed char] *)
| IUChar (** [unsigned char] *)
| IBool (** [bool] *)
| IInt (** [int] *)
| IUInt (** [unsigned int] *)
| IShort (** [short] *)
| IUShort (** [unsigned short] *)
| ILong (** [long] *)
| IULong (** [unsigned long] *)
| ILongLong (** [long long] (or [_int64] on Microsoft Visual C) *)
| IULongLong (** [unsigned long long] (or [unsigned _int64] on Microsoft Visual C) *)
| I128 (** [__int128_t] *)
| IU128 (** [__uint128_t] *)
[@@deriving compare]
val ikind_is_char : ikind -> bool
(** Check whether the integer kind is a char *)
val ikind_is_unsigned : ikind -> bool
(** Check whether the integer kind is unsigned *)
(** Kinds of floating-point numbers *)
type fkind =
| FFloat (** [float] *)
| FDouble (** [double] *)
| FLongDouble (** [long double] *)
[@@deriving compare]
(** kind of pointer *)
type ptr_kind =
| Pk_pointer (** C/C++, Java, Objc standard/__strong pointer *)
| Pk_reference (** C++ reference *)
| Pk_objc_weak (** Obj-C __weak pointer *)
| Pk_objc_unsafe_unretained (** Obj-C __unsafe_unretained pointer *)
| Pk_objc_autoreleasing (** Obj-C __autoreleasing pointer *)
[@@deriving compare]
val equal_ptr_kind : ptr_kind -> ptr_kind -> bool
type type_quals [@@deriving compare]
val mk_type_quals :
?default:type_quals -> ?is_const:bool -> ?is_restrict:bool -> ?is_volatile:bool -> unit
-> type_quals
val is_const : type_quals -> bool
val is_restrict : type_quals -> bool
val is_volatile : type_quals -> bool
(** types for sil (structured) expressions *)
type t = {desc: desc; quals: type_quals} [@@deriving compare]
and desc =
| Tint of ikind (** integer type *)
| Tfloat of fkind (** float type *)
| Tvoid (** void type *)
| Tfun of {no_return: bool} (** function type with noreturn attribute *)
| Tptr of t * ptr_kind (** pointer type *)
| Tstruct of name (** structured value type name *)
| TVar of string (** type variable (ie. C++ template variables) *)
| Tarray of {elt: t; length: IntLit.t option; stride: IntLit.t option}
(** array type with statically fixed length and stride *)
[@@deriving compare]
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<int>::InnerClass<int> will store
"MyClass<int>", "InnerClass" *)
| CppClass of QualifiedCppName.t * template_spec_info
| JavaClass of Mangled.t
| ObjcClass of QualifiedCppName.t
| ObjcProtocol of QualifiedCppName.t
[@@deriving compare]
and template_arg = TType of t | TInt of Int64.t | TNull | TNullPtr | TOpaque [@@deriving compare]
and template_spec_info =
| NoTemplate
| Template of
{ mangled: string option
(** WARNING: because of type substitutions performed by [sub_type] and [sub_tname],
mangling is not guaranteed to be unique to a single type. All the information in
the template arguments is also needed for uniqueness. *)
; args: template_arg list }
[@@deriving compare]
val mk : ?default:t -> ?quals:type_quals -> desc -> t
(** Create Typ.t from given desc. if [default] is passed then use its value to set other fields such as quals *)
val mk_array : ?default:t -> ?quals:type_quals -> ?length:IntLit.t -> ?stride:IntLit.t -> t -> t
(** Create an array type from a given element type. If [length] or [stride] value is given, use them as static length and size. *)
val void : t
(** void type *)
val void_star : t
(** void* type *)
(** Stores information about type substitution *)
type type_subst_t [@@deriving compare]
module Name : sig
(** Named types. *)
type t = name [@@deriving compare]
val equal : t -> t -> bool
(** Equality for typenames *)
val to_string : t -> string
(** convert the typename to a string *)
val pp : Format.formatter -> t -> unit
val is_class : t -> bool
(** [is_class name] holds if [name] names CPP/Objc/Java class *)
val is_union : t -> bool
(** [is_union name] holds if [name] names C/CPP union *)
val is_same_type : t -> t -> bool
(** [is_class name1 name2] holds if [name1] and [name2] name same kind of type *)
val name : t -> string
(** name of the typename without qualifier *)
val qual_name : t -> QualifiedCppName.t
(** qualified name of the type, may return nonsense for Java classes *)
val unqualified_name : t -> QualifiedCppName.t
module C : sig
val from_string : string -> t
val from_qual_name : QualifiedCppName.t -> t
val union_from_qual_name : QualifiedCppName.t -> t
end
module Java : sig
module Split : sig
type t
val make : ?package:string -> string -> t
val java_lang_object : t
val java_lang_string : t
val package : t -> string option
val type_name : t -> string
end
val from_string : string -> t
(** Create a typename from a Java classname in the form "package.class" *)
val from_package_class : string -> string -> t
(** Create a typename from a package name and a class name *)
val is_class : t -> bool
(** [is_class name] holds if [name] names a Java class *)
val is_external_classname : string -> bool
(** return true if the string is in the .inferconfig list of external classes *)
val is_external : t -> bool
(** return true if the typename is in the .inferconfig list of external classes *)
val get_outer_class : t -> t option
(** Given an inner classname like C$Inner1$Inner2, return Some C$Inner1. If the class is not an
inner class, return None *)
val java_lang_object : t
val java_io_serializable : t
val java_lang_cloneable : t
end
module Cpp : sig
val from_qual_name : template_spec_info -> QualifiedCppName.t -> t
(** Create a typename from a C++ classname *)
val is_class : t -> bool
(** [is_class name] holds if [name] names a C++ class *)
end
module Objc : sig
val from_string : string -> t
(** Create a typename from a Objc classname *)
val from_qual_name : QualifiedCppName.t -> t
val protocol_from_qual_name : QualifiedCppName.t -> t
end
module Set : Caml.Set.S with type elt = t
end
val equal : t -> t -> bool
(** Equality for types. *)
val equal_desc : desc -> desc -> bool
val equal_quals : type_quals -> type_quals -> bool
val sub_type : type_subst_t -> t -> t
val sub_tname : type_subst_t -> Name.t -> Name.t
val is_type_subst_empty : type_subst_t -> bool
val pp_full : Pp.env -> F.formatter -> t -> unit
(** Pretty print a type with all the details. *)
val pp : Pp.env -> F.formatter -> t -> unit
(** Pretty print a type. *)
val to_string : t -> string
val d_full : t -> unit
(** Dump a type with all the details. *)
val d_list : t list -> unit
(** Dump a list of types. *)
val name : t -> Name.t option
(** The name of a type *)
val inner_name : t -> Name.t option
(** Name of the type of a Tstruct pointed to by a Tptr *)
val strip_ptr : t -> t
(** turn a *T into a T. fails if [t] is not a pointer type *)
val array_elem : t option -> t -> t
(** If an array type, return the type of the element.
If not, return the default type if given, otherwise raise an exception *)
val is_objc_class : t -> bool
val is_cpp_class : t -> bool
val is_pointer_to_cpp_class : t -> bool
val is_pointer : t -> bool
val is_array : t -> bool
val is_reference : t -> bool
val has_block_prefix : string -> bool
val unsome : string -> t option -> t
type typ = t
module Procname : sig
(** Module for Procedure Names. *)
(** Type of java procedure names. *)
module Java : sig
type kind =
| Non_Static
(** in Java, procedures called with invokevirtual, invokespecial, and invokeinterface *)
| Static (** in Java, procedures called with invokestatic *)
type t [@@deriving compare]
type java_type = Name.Java.Split.t
val constructor_method_name : string
val class_initializer_method_name : string
val compare_java_type : java_type -> java_type -> int
val make : Name.t -> java_type option -> string -> java_type list -> kind -> t
(** Create a Java procedure name from its
class_name method_name args_type_name return_type_name method_kind. *)
val replace_method_name : string -> t -> t
(** Replace the method name of an existing java procname. *)
val replace_parameters : java_type list -> t -> t
(** Replace the parameters of a java procname. *)
val replace_return_type : java_type -> t -> t
(** Replace the method of a java procname. *)
val get_class_name : t -> string
(** Return the class name of a java procedure name. *)
val get_class_type_name : t -> Name.t
(** Return the class name as a typename of a java procedure name. *)
val get_simple_class_name : t -> string
(** Return the simple class name of a java procedure name. *)
val get_package : t -> string option
(** Return the package name of a java procedure name. *)
val get_method : t -> string
(** Return the method name of a java procedure name. *)
val get_parameters : t -> java_type list
(** Return the parameters of a java procedure name. *)
val get_return_typ : t -> typ
(** Return the return type of [pname_java]. return Tvoid if there's no return type *)
val is_access_method : t -> bool
(** Check if the procedure name is an acess method (e.g. access$100 used to
access private members from a nested class. *)
val is_autogen_method : t -> bool
(** Check if the procedure name is of an auto-generated method containing '$'. *)
val is_anonymous_inner_class_constructor : t -> bool
(** Check if the procedure name is an anonymous inner class constructor. *)
val is_close : t -> bool
(** Check if the method name is "close". *)
val is_static : t -> bool
(** Check if the java procedure is static. *)
val is_vararg : t -> bool
(** Check if the proc name has the type of a java vararg.
Note: currently only checks that the last argument has type Object[]. *)
val is_lambda : t -> bool
(** Check if the proc name comes from a lambda expression *)
val is_generated : t -> bool
(** Check if the proc name comes from generated code *)
val is_class_initializer : t -> bool
(** Check if this is a class initializer. *)
val is_external : t -> bool
(** Check if the method belongs to one of the specified external packages *)
end
module Parameter : sig
(** Type for parameters in clang procnames, [Some name] means the parameter is of type pointer to struct, with [name]
being the name of the struct, [None] means the parameter is of some other type. *)
type clang_parameter = Name.t option [@@deriving compare]
(** Type for parameters in procnames, for java and clang. *)
type t = JavaParameter of Java.java_type | ClangParameter of clang_parameter
[@@deriving compare]
val of_typ : typ -> clang_parameter
end
module ObjC_Cpp : sig
type kind =
| CPPMethod of {mangled: string option}
| CPPConstructor of {mangled: string option; is_constexpr: bool}
| CPPDestructor of {mangled: string option}
| ObjCClassMethod
| ObjCInstanceMethod
| ObjCInternalMethod
[@@deriving compare]
(** Type of Objective C and C++ procedure names: method signatures. *)
type t =
{ class_name: Name.t
; kind: kind
; method_name: string
; parameters: Parameter.clang_parameter list
; template_args: template_spec_info }
[@@deriving compare]
val make :
Name.t -> string -> kind -> template_spec_info -> Parameter.clang_parameter list -> t
(** Create an objc procedure name from a class_name and method_name. *)
val get_class_name : t -> string
val get_class_type_name : t -> Name.t
val get_class_qualifiers : t -> QualifiedCppName.t
val objc_method_kind_of_bool : bool -> kind
(** Create ObjC method type from a bool is_instance. *)
val is_objc_constructor : string -> bool
(** Check if this is a constructor method in Objective-C. *)
val is_objc_dealloc : string -> bool
(** Check if this is a dealloc method in Objective-C. *)
val is_destructor : t -> bool
(** Check if this is a dealloc method. *)
val is_inner_destructor : t -> bool
(** Check if this is a frontend-generated "inner" destructor (see D5834555/D7189239) *)
val is_constexpr : t -> bool
(** Check if this is a constexpr function. *)
val is_cpp_lambda : t -> bool
(** Return whether the procname is a cpp lambda. *)
val is_operator_equal : t -> bool
(** Return true if the procname is operator= *)
end
module C : sig
(** Type of c procedure names. *)
type t = private
{ name: QualifiedCppName.t
; mangled: string option
; parameters: Parameter.clang_parameter list
; template_args: template_spec_info }
val c :
QualifiedCppName.t -> string -> Parameter.clang_parameter list -> template_spec_info -> t
(** Create a C procedure name from plain and mangled name. *)
end
module Block : sig
(** Type of Objective C block names. *)
type block_name = string
type t = {name: block_name; parameters: Parameter.clang_parameter list} [@@deriving compare]
val make : block_name -> Parameter.clang_parameter list -> t
end
(** Type of procedure names.
WithBlockParameters is used for creating an instantiation of a method that contains block parameters
and it's called with concrete blocks. For example:
foo(Block block) {block();}
bar() {foo(my_block)} is executed as foo_my_block() {my_block(); }
where foo_my_block is created with WithBlockParameters (foo, [my_block]) *)
type t =
| Java of Java.t
| C of C.t
| Linters_dummy_method
| Block of Block.t
| ObjC_Cpp of ObjC_Cpp.t
| WithBlockParameters of t * Block.block_name list
[@@deriving compare]
val block_name_of_procname : t -> Block.block_name
val equal : t -> t -> bool
val get_parameters : t -> Parameter.t list
val replace_parameters : Parameter.t list -> t -> t
val parameter_of_name : t -> Name.t -> Parameter.t
val is_objc_method : t -> bool
(** Hash tables with proc names as keys. *)
module Hash : Caml.Hashtbl.S with type key = t
(** Maps from proc names. *)
module Map : PrettyPrintable.PPMap with type key = t
(** Sets of proc names. *)
module Set : PrettyPrintable.PPSet with type elt = t
module SQLite : sig
val serialize : t -> Sqlite3.Data.t
val deserialize : Sqlite3.Data.t -> t
val clear_cache : unit -> unit
end
module SQLiteList : SqliteUtils.Data with type t = t list
val empty_block : t
(** Empty block name. *)
val get_language : t -> Language.t
(** Return the language of the procedure. *)
val get_method : t -> string
(** Return the method/function of a procname. *)
val is_objc_block : t -> bool
(** Return whether the procname is a block procname. *)
val hash_pname : t -> int
(** Hash function for procname. *)
val is_c_method : t -> bool
(** Return true this is an Objective-C/C++ method name. *)
val is_clang : t -> bool
(** Return true if this is a C, C++, or Objective-C procedure name *)
val is_constructor : t -> bool
(** Check if this is a constructor. *)
val is_java : t -> bool
(** Check if this is a Java procedure name. *)
val with_block_parameters : t -> Block.block_name list -> t
(** Create a procedure name instantiated with block parameters from a base procedure name
and a list of block procedure names (the arguments). *)
val objc_cpp_replace_method_name : t -> string -> t
val is_infer_undefined : t -> bool
(** Check if this is a special Infer undefined procedure. *)
val get_global_name_of_initializer : t -> string option
(** Return the name of the global for which this procedure is the initializer if this is an
initializer, None otherwise. *)
val pp : Format.formatter -> t -> unit
(** Pretty print a proc name. *)
val replace_class : t -> Name.t -> t
(** Replace the class name component of a procedure name.
In case of Java, replace package and class name. *)
val is_method_in_objc_protocol : t -> bool
val to_string : t -> string
(** Convert a proc name to a string for the user to see. *)
val to_simplified_string : ?withclass:bool -> t -> string
(** Convert a proc name into a easy string for the user to see in an IDE. *)
val from_string_c_fun : string -> t
(** Convert a string to a c function name. *)
val hashable_name : t -> string
(** Print the procedure name in a format suitable for computing the bug hash *)
val to_unique_id : t -> string
(** Convert a proc name into a unique identifier. *)
val to_filename : ?crc_only:bool -> t -> string
(** Convert a proc name to a filename or only to its crc. *)
val get_qualifiers : t -> QualifiedCppName.t
(** get qualifiers of C/objc/C++ method/function *)
end
module Fieldname : sig
(** Names for fields of class/struct/union *)
type t [@@deriving compare]
val equal : t -> t -> bool
(** Equality for field names. *)
(** Set for fieldnames *)
module Set : Caml.Set.S with type elt = t
(** Map for fieldnames *)
module Map : Caml.Map.S with type key = t
module Clang : sig
val from_class_name : Name.t -> string -> t
end
module Java : sig
val from_string : string -> t
(** Create a java field name from string *)
val is_captured_parameter : t -> bool
(** Check if field is a captured parameter *)
val get_class : t -> string
(** The class part of the fieldname *)
val get_field : t -> string
(** The last component of the fieldname *)
val is_outer_instance : t -> bool
(** Check if the field is the synthetic this$n of a nested class, used to access the n-th outer
instance. *)
end
val to_string : t -> string
(** Convert a field name to a string. *)
val to_full_string : t -> string
val class_name_replace : t -> f:(Name.t -> Name.t) -> t
val to_simplified_string : t -> string
(** Convert a fieldname to a simplified string with at most one-level path. *)
val to_flat_string : t -> string
(** Convert a fieldname to a flat string without path. *)
val pp : Format.formatter -> t -> unit
(** Pretty print a field name. *)
val clang_get_qual_class : t -> QualifiedCppName.t option
(** get qualified classname of a field if it's coming from clang frontend. returns None otherwise *)
end
module Struct : sig
type field = Fieldname.t * typ * Annot.Item.t [@@deriving compare]
type fields = field list
(** Type for a structured value. *)
type t = private
{ fields: fields (** non-static fields *)
; statics: fields (** static fields *)
; supers: Name.t list (** supers *)
; methods: Procname.t list (** methods defined *)
; annots: Annot.Item.t (** annotations *) }
type lookup = Name.t -> t option
val pp_field : Pp.env -> F.formatter -> field -> unit
val pp : Pp.env -> Name.t -> F.formatter -> t -> unit
(** Pretty print a struct type. *)
val internal_mk_struct :
?default:t -> ?fields:fields -> ?statics:fields -> ?methods:Procname.t list
-> ?supers:Name.t list -> ?annots:Annot.Item.t -> unit -> t
(** Construct a struct_typ, normalizing field types *)
val get_extensible_array_element_typ : lookup:lookup -> typ -> typ option
(** the element typ of the final extensible array in the given typ, if any *)
val fld_typ : lookup:lookup -> default:typ -> Fieldname.t -> typ -> typ
(** If a struct type with field f, return the type of f.
If not, return the default type if given, otherwise raise an exception *)
val get_field_type_and_annotation :
lookup:lookup -> Fieldname.t -> typ -> (typ * Annot.Item.t) option
(** Return the type of the field [fn] and its annotation, None if [typ] has no field named [fn] *)
end