[clang] [1 of 3] Replacing parser of types

Summary:
This is the first of 3 stack diffs to replace the parser of types in the clang frontend.
In this diff we remove the parser and the lexer and add a new module that does the
translation from ast types to sil types.
It is still incomplete, i.e. many c++ types are still not treated. However, all the
types that we were previously treating in C and ObjC are treated and some C++ ones, such
that the tests pass and we get good results in the apps.
Sometimes one needs to translate a record type when we havent translated the record itself,
so the translation of types and of records needs to be mutual recursive. I managed however
to get them into different modules and achieve the mutual recursion using higher order functions.
master
Dulma Rodriguez 9 years ago
parent a538998ed9
commit 8e547d197d

@ -1,146 +0,0 @@
(*
* Copyright (c) 2013 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
(* Lexer to support a parser of types *)
{
open CTypes_parser
let line_number = ref 1
let parentheses = ref 0
let parsed_tokens = Buffer.create 1
let log lexbuf = Buffer.add_char parsed_tokens ' '; Buffer.add_string parsed_tokens (Lexing.lexeme lexbuf)
let reset_log () = Buffer.reset parsed_tokens
let get_log () = Buffer.contents parsed_tokens
let attr_par = ref 0
let attr_buf = Buffer.create 1
let reset_attr_buf () = Buffer.reset attr_buf
let log_attr_buf lexbuf =
Buffer.add_string parsed_tokens (Lexing.lexeme lexbuf);
Buffer.add_string attr_buf (Lexing.lexeme lexbuf)
let get_attr_buf () = Buffer.contents attr_buf
}
let lowerletter = ['a'-'z']
let upperletter = ['A'-'Z']
let underscore = '_'
let minus = '-'
let letter = lowerletter | upperletter
let digit = ['0'-'9']
let number = digit* | digit+ '.' digit* | digit* '.' digit+
let space = [' ' '\t']
let identifier = (letter | underscore) (letter | underscore | digit | ':')*
let anonymous_identifier = '(' 'a' 'n' 'o' 'n' 'y' 'm' 'o' 'u' 's' (letter | underscore | digit | ' ' | '.' | ':' | '/' | minus)* ')'
let nested_anonymous_identifier = (identifier ':' ':')+ (anonymous_identifier | identifier)
let nested_identifier = identifier (':' ':' identifier)+
let char = letter | digit
let hexa_digit = ['0'-'9' 'a'-'f']
let hexa = '0' 'x' hexa_digit*
let dir_sep = '/'
let dot = '.'
let extension = dot ('c' | 'h' | 'm')
let basename = (char | underscore | minus | dot )+
let filename = basename extension
let path = (dir_sep basename | basename)* filename
let attribute_digit = letter | underscore | digit | '(' | ')' | '\"' | ","
let newline = '\n'
rule token = parse
| space { log lexbuf; token lexbuf }
| newline { log lexbuf; incr line_number; token lexbuf }
| '.' { log lexbuf; DOT }
| ';' { log lexbuf; SEMICOLON }
| ':' { log lexbuf; COLON }
| ',' { log lexbuf; COMMA }
| '\'' { log lexbuf; SINGLE_QUOTE }
| '`' { log lexbuf; REV_QUOTE }
| '\"' { log lexbuf; DOUBLE_QUOTE }
| '^' { log lexbuf; CARRET }
| "class" { log lexbuf; CLASS }
| "struct" { log lexbuf; STRUCT }
| "union" { log lexbuf; UNION }
| "enum" { log lexbuf; ENUM }
| "unsigned" { log lexbuf; UNSIGNED }
| "signed" { log lexbuf; SIGNED }
| "void" { log lexbuf; VOID }
| "char" { log lexbuf; CHAR }
| "short" { log lexbuf; SHORT }
| "int" { log lexbuf; INT }
| "long" { log lexbuf; LONG }
| "_Bool" { log lexbuf; UND_BOOL }
| "__uint16_" { log lexbuf; UND_UND_UINT16_ }
| "__uint16_t" { log lexbuf; UND_UND_UINT16_T }
| "__uint32_" { log lexbuf; UND_UND_UINT32_ }
| "__uint32_t" { log lexbuf; UND_UND_UINT32_T }
| "__int32_t" { log lexbuf; UND_UND_INT32_T }
| "__int64_t" { log lexbuf; UND_UND_INT64_T }
| "__uint64_t" { log lexbuf; UND_UND_UINT64_T }
| "UInt8" { log lexbuf; UINT8 }
| "UInt16" { log lexbuf; UINT16 }
| "UInt32" { log lexbuf; UINT32 }
| "UInt64" { log lexbuf; UINT64 }
| "float" { log lexbuf; FLOAT }
| "double" { log lexbuf; DOUBLE }
| "volatile" { log lexbuf; VOLATILE }
| "*volatile" { log lexbuf; STARVOLATILE }
| "<builtin fn type>" { log lexbuf; BUILTIN_FN_TYPE}
| "inline" { log lexbuf; INLINE }
| "typename" { log lexbuf; TYPENAME }
| "const" { log lexbuf; CONST }
| "*const" { log lexbuf; STARCONST }
| "__strong" { log lexbuf; UND_UND_STRONG }
| "__unsafe_unretained" { log lexbuf; UND_UND_UNSAFE_UNRETAINED }
| "__weak" { log lexbuf; UND_UND_WEAK }
| "__autoreleasing" { log lexbuf; UND_UND_AUTORELEASING }
| "*__strong" { log lexbuf; STAR_UND_UND_STRONG }
| "*__unsafe_unretained" { log lexbuf; STAR_UND_UND_UNSAFE_UNRETAINED }
| "*__weak" { log lexbuf; STAR_UND_UND_WEAK }
| "*__autoreleasing" { log lexbuf; STAR_UND_UND_AUTORELEASING }
| "noexcept" { log lexbuf; NOEXCEPT }
| "restrict" { log lexbuf; RESTRICT }
| '%' { log lexbuf; PERCENT }
| '&' { log lexbuf; AMPERSAND }
| '!' { log lexbuf; EXCLAMATION }
| '=' { log lexbuf; EQUAL }
| '-' { log lexbuf; MINUS }
| '+' { log lexbuf; PLUS }
| '<' { log lexbuf; LEFT_CHEVRON }
| '>' { log lexbuf; RIGHT_CHEVRON }
| '(' { log lexbuf; incr parentheses; LEFT_PARENTHESIS }
| ')' { log lexbuf; decr parentheses; RIGHT_PARENTHESIS }
| '[' { log lexbuf; LEFT_SQBRACKET }
| ']' { log lexbuf; RIGHT_SQBRACKET }
| '{' { log lexbuf; LEFT_BRACE }
| '}' { log lexbuf; RIGHT_BRACE }
| '*' { log lexbuf; STAR }
| '|' { log lexbuf; PIPE }
| '/' { log lexbuf; SLASH }
| '\\' { log lexbuf; BACKSLASH }
| hexa as s { log lexbuf; HEXA (s) }
| number as n { log lexbuf; NUMBER n }
| identifier as s { log lexbuf; IDENT (s) }
| anonymous_identifier as s { log lexbuf; ANONYM_IDENT (s) }
| nested_identifier as s { log lexbuf; NESTED_IDENT (s) }
| nested_anonymous_identifier as s { log lexbuf; NESTED_ANONYM_IDENT (s) }
| eof { EOF }

@ -40,7 +40,7 @@ let rec translate_one_declaration tenv cg cfg namespace parent_dec dec =
(* Currently C/C++ record decl treated in the same way *) (* Currently C/C++ record decl treated in the same way *)
| CXXRecordDecl (_, _, _, _, decl_list, _, _, _) | CXXRecordDecl (_, _, _, _, decl_list, _, _, _)
| RecordDecl (_, _, _, _, decl_list, _, _) -> | RecordDecl (_, _, _, _, decl_list, _, _) ->
CTypes_decl.add_types_from_decl_to_tenv tenv namespace dec; ignore (CTypes_decl.add_types_from_decl_to_tenv tenv namespace dec);
let method_decls = CTypes_decl.get_method_decls dec decl_list in let method_decls = CTypes_decl.get_method_decls dec decl_list in
let tranlate_method (parent, decl) = let tranlate_method (parent, decl) =
translate_one_declaration tenv cg cfg namespace parent decl in translate_one_declaration tenv cg cfg namespace parent decl in

@ -149,3 +149,15 @@ let ns_array_ptr = "NSArray *"
let enumerateObjectsUsingBlock = "enumerateObjectsUsingBlock:" let enumerateObjectsUsingBlock = "enumerateObjectsUsingBlock:"
let generated_suffix = "*generated" let generated_suffix = "*generated"
let pointer_type_index = ref Clang_ast_main.PointerMap.empty
let sil_types_map = ref Clang_ast_main.PointerMap.empty
let weak_attribute = "__weak"
let strong_attribtue = "__strong"
let unsafe_unretained_attribute = "__unsafe_unretained"
let autoreleasing_atribute = "__autoreleasing"

@ -146,3 +146,15 @@ val ns_array_ptr : string
val enumerateObjectsUsingBlock : string val enumerateObjectsUsingBlock : string
val generated_suffix : string val generated_suffix : string
val pointer_type_index : Clang_ast_t.c_type Clang_ast_main.PointerMap.t ref
val sil_types_map : (Sil.typ Clang_ast_main.PointerMap.t) ref
val weak_attribute : string
val strong_attribtue : string
val unsafe_unretained_attribute : string
val autoreleasing_atribute : string

@ -263,6 +263,10 @@ struct
Some (Clang_ast_main.PointerMap.find decl_ptr !CFrontend_config.pointer_decl_index) Some (Clang_ast_main.PointerMap.find decl_ptr !CFrontend_config.pointer_decl_index)
with Not_found -> Printing.log_stats "decl with pointer %s not found\n" decl_ptr; None with Not_found -> Printing.log_stats "decl with pointer %s not found\n" decl_ptr; None
let update_sil_types_map type_ptr sil_type =
CFrontend_config.sil_types_map :=
Clang_ast_main.PointerMap.add type_ptr sil_type !CFrontend_config.sil_types_map
end end
(* Global counter for anonymous block*) (* Global counter for anonymous block*)

@ -77,6 +77,8 @@ sig
val get_decl : Clang_ast_t.pointer -> Clang_ast_t.decl option val get_decl : Clang_ast_t.pointer -> Clang_ast_t.decl option
val update_sil_types_map : Clang_ast_t.pointer -> Sil.typ -> unit
end end
module General_utils : module General_utils :

@ -101,8 +101,9 @@ let do_run source_path ast_path =
Printing.log_out "Original AST@.%a@." CAstProcessor.pp_ast_decl ast_decl; Printing.log_out "Original AST@.%a@." CAstProcessor.pp_ast_decl ast_decl;
Printing.log_out "AST with explicit locations:@.%a@." CAstProcessor.pp_ast_decl ast_decl'; Printing.log_out "AST with explicit locations:@.%a@." CAstProcessor.pp_ast_decl ast_decl';
let decl_index, _, _ = Clang_ast_main.index_node_pointers ast_decl' in let decl_index, _, type_index = Clang_ast_main.index_node_pointers ast_decl' in
CFrontend_config.pointer_decl_index := decl_index; CFrontend_config.pointer_decl_index := decl_index;
CFrontend_config.pointer_type_index := type_index;
CFrontend_config.json := ast_filename; CFrontend_config.json := ast_filename;
CLocation.check_source_file source_path; CLocation.check_source_file source_path;
let source_file = CLocation.source_file_from_path source_path in let source_file = CLocation.source_file_from_path source_path in

@ -0,0 +1,169 @@
(*
* Copyright (c) 2013 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open CFrontend_utils
let custom_qual_type_to_sil_type type_pointer =
if Utils.string_is_prefix "custom" type_pointer then
let typ =
(match CTypes.get_name_from_type_pointer type_pointer with
| "custom_class_name", class_name -> Sil.Tvar (CTypes.mk_classname class_name)
| "custom_pointer_custom_class_name", class_name ->
Sil.Tptr (Sil.Tvar (CTypes.mk_classname class_name), Sil.Pk_pointer)
| "custom_struct_name", struct_name -> Sil.Tvar (CTypes.mk_structname struct_name)
| "custom_pointer_custom_struct_name", struct_name ->
Sil.Tptr (Sil.Tvar (CTypes.mk_structname struct_name), Sil.Pk_pointer)
| _ -> assert false) in
Some typ
else None
let get_builtin_objc_typename builtin_type =
match builtin_type with
| `ObjCId -> Sil.TN_csu (Sil.Struct, (Mangled.from_string CFrontend_config.objc_object))
| `ObjCClass -> Sil.TN_csu (Sil.Struct, (Mangled.from_string CFrontend_config.objc_class))
let get_builtin_objc_type builtin_type =
let typ = Sil.Tvar (get_builtin_objc_typename builtin_type) in
match builtin_type with
| `ObjCId -> typ
| `ObjCClass -> Sil.Tptr (typ, Sil.Pk_pointer)
let sil_type_of_builtin_type_kind builtin_type_kind =
match builtin_type_kind with
| `Void -> Sil.Tvoid
| `Bool -> Sil.Tint Sil.IBool
| `Char_U -> Sil.Tint Sil.IUChar
| `UChar -> Sil.Tint Sil.IUChar
| `WChar_U -> Sil.Tint Sil.IUChar
| `Char_S -> Sil.Tint Sil.IChar
| `SChar -> Sil.Tint Sil.ISChar
| `WChar_S
| `Char16
| `Char32 -> Sil.Tint Sil.IChar
| `UShort
| `Short -> Sil.Tint Sil.IShort
| `UInt
| `UInt128 -> Sil.Tint Sil.IUInt
| `ULong -> Sil.Tint Sil.IULong
| `ULongLong -> Sil.Tint Sil.IULongLong
| `Int
| `Int128 -> Sil.Tint Sil.IInt
| `Long -> Sil.Tint Sil.ILong
| `LongLong -> Sil.Tint Sil.ILongLong
| `Half -> Sil.Tint Sil.IShort (*?*)
| `Float -> Sil.Tfloat Sil.FFloat
| `Double -> Sil.Tfloat Sil.FDouble
| `LongDouble -> Sil.Tfloat Sil.FLongDouble
| `NullPtr -> Sil.Tint Sil.IInt
| `ObjCId -> get_builtin_objc_type `ObjCId
| `ObjCClass -> get_builtin_objc_type `ObjCClass
| _ -> Sil.Tvoid
let rec build_array_type translate_decl tenv type_ptr n =
let array_type = qual_type_ptr_to_sil_type translate_decl tenv type_ptr in
let exp = Sil.exp_int (Sil.Int.of_int64 (Int64.of_int n)) in
Sil.Tarray (array_type, exp)
and sil_type_of_c_type translate_decl tenv c_type =
let open Clang_ast_t in
match c_type with
| NoneType (type_info) -> Sil.Tvoid
| BuiltinType (type_info, builtin_type_kind) ->
sil_type_of_builtin_type_kind builtin_type_kind
| PointerType (type_info, type_ptr)
| ObjCObjectPointerType (type_info, type_ptr) ->
let typ = qual_type_ptr_to_sil_type translate_decl tenv type_ptr in
if Sil.typ_equal typ (get_builtin_objc_type `ObjCClass) then
typ
else Sil.Tptr (typ, Sil.Pk_pointer)
| ObjCObjectType (type_info, objc_object_type_info) ->
qual_type_ptr_to_sil_type translate_decl tenv objc_object_type_info.Clang_ast_t.base_type
| BlockPointerType (type_info, type_ptr) ->
let typ = qual_type_ptr_to_sil_type translate_decl tenv type_ptr in
Sil.Tptr (typ, Sil.Pk_pointer)
| IncompleteArrayType (type_info, type_ptr)
| DependentSizedArrayType (type_info, type_ptr)
| VariableArrayType (type_info, type_ptr) ->
build_array_type translate_decl tenv type_ptr (-1)
| ConstantArrayType (type_info, type_ptr, n) ->
build_array_type translate_decl tenv type_ptr n
| FunctionProtoType (type_info, function_type_info, _)
| FunctionNoProtoType (type_info, function_type_info) ->
Sil.Tfun false
| ParenType (type_info, type_ptr) ->
qual_type_ptr_to_sil_type translate_decl tenv type_ptr
| DecayedType (type_info, type_ptr) ->
qual_type_ptr_to_sil_type translate_decl tenv type_ptr
| RecordType (type_info, pointer)
| EnumType (type_info, pointer) ->
decl_ptr_to_sil_type translate_decl tenv pointer
| ElaboratedType (type_info) ->
(match type_info.Clang_ast_t.ti_desugared_type with
Some type_ptr -> qual_type_ptr_to_sil_type translate_decl tenv type_ptr
| None -> Sil.Tvoid)
| ObjCInterfaceType (type_info, pointer) ->
decl_ptr_to_sil_type translate_decl tenv pointer
| LValueReferenceType (type_info, type_ptr) ->
let typ = qual_type_ptr_to_sil_type translate_decl tenv type_ptr in
Sil.Tptr (typ, Sil.Pk_reference)
| AttributedType type_info ->
(match type_info.Clang_ast_t.ti_desugared_type with
| Some type_ptr ->
(match Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.pointer_type_index with
| ObjCObjectPointerType (type_info', type_ptr') ->
let typ = qual_type_ptr_to_sil_type translate_decl tenv type_ptr' in
CTypes.sil_type_of_attr_pointer_type typ type_info.Clang_ast_t.ti_raw
| _ -> qual_type_ptr_to_sil_type translate_decl tenv type_ptr)
| None -> Sil.Tvoid)
| _ -> (* TypedefType, etc *)
let type_info = Clang_ast_proj.get_type_tuple c_type in
match type_info.Clang_ast_t.ti_desugared_type with
| Some typ -> qual_type_ptr_to_sil_type translate_decl tenv typ
| None -> Sil.Tvoid
and decl_ptr_to_sil_type translate_decl tenv decl_ptr =
let open Clang_ast_t in
try Clang_ast_main.PointerMap.find decl_ptr !CFrontend_config.sil_types_map
with Not_found ->
match Ast_utils.get_decl decl_ptr with
| Some (ObjCInterfaceDecl(decl_info, name_info, decl_list, decl_context_info, oidi)) ->
Sil.Tvar (CTypes.mk_classname name_info.Clang_ast_t.ni_name)
| Some (CXXRecordDecl _ as d)
| Some (RecordDecl _ as d) -> translate_decl tenv None d
| Some (EnumDecl(_, name_info, _, _, _, _, _) ) ->
Sil.Tvar (CTypes.mk_enumname name_info.Clang_ast_t.ni_name)
| Some _ ->
Printing.log_err "Warning: Wrong decl found for pointer %s "
(Clang_ast_j.string_of_pointer decl_ptr);
Sil.Tvoid
| None ->
Printing.log_err "Warning: Decl pointer %s not found."
(Clang_ast_j.string_of_pointer decl_ptr);
Sil.Tvoid
and qual_type_ptr_to_sil_type translate_decl tenv type_ptr =
try
Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.sil_types_map
with Not_found ->
try
let c_type = Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.pointer_type_index in
let sil_type = sil_type_of_c_type translate_decl tenv c_type in
Ast_utils.update_sil_types_map type_ptr sil_type;
sil_type
with Not_found ->
Printing.log_err "Warning: Type pointer %s not found."
(Clang_ast_j.string_of_pointer type_ptr);
Sil.Tvoid
and qual_type_to_sil_type translate_decl tenv qt =
let type_ptr = qt.Clang_ast_t.qt_type_ptr in
match custom_qual_type_to_sil_type type_ptr with
| Some typ -> typ
| None -> qual_type_ptr_to_sil_type translate_decl tenv type_ptr

@ -0,0 +1,17 @@
(*
* Copyright (c) 2013 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
val get_builtin_objc_typename : [< `ObjCClass | `ObjCId ] -> Sil.typename
val get_builtin_objc_type : [< `ObjCClass | `ObjCId ] -> Sil.typ
val sil_type_of_builtin_type_kind : Clang_ast_t.builtin_type_kind -> Sil.typ
val qual_type_to_sil_type : (Sil.tenv -> string option -> Clang_ast_t.decl -> Sil.typ) ->
Sil.tenv -> Clang_ast_t.qual_type -> Sil.typ

@ -195,8 +195,11 @@ let search_enum_type_by_name tenv name =
Sil.tenv_iter f tenv; Sil.tenv_iter f tenv;
!found !found
let mk_classname n = let mk_classname n = Sil.TN_csu (Sil.Class, Mangled.from_string n)
Sil.TN_csu (Sil.Class, Mangled.from_string n)
let mk_structname n = Sil.TN_csu (Sil.Struct, Mangled.from_string n)
let mk_enumname n = Sil.TN_enum (Mangled.from_string n)
let is_class typ = let is_class typ =
match typ with match typ with
@ -204,3 +207,58 @@ let is_class typ =
| Sil.Tptr( Sil.Tvar (Sil.TN_csu (_, name) ), _) -> | Sil.Tptr( Sil.Tvar (Sil.TN_csu (_, name) ), _) ->
(Mangled.to_string name) = CFrontend_config.objc_class (Mangled.to_string name) = CFrontend_config.objc_class
| _ -> false | _ -> false
let sil_type_of_attr_pointer_type typ raw_type =
let pointer_attribute_of_objc_attribute objc_attribute =
if Utils.string_is_suffix CFrontend_config.weak_attribute objc_attribute
then Sil.Pk_objc_weak
else if Utils.string_is_suffix CFrontend_config.strong_attribtue objc_attribute
then Sil.Pk_pointer
else if Utils.string_is_suffix CFrontend_config.unsafe_unretained_attribute objc_attribute
then Sil.Pk_objc_unsafe_unretained
else if Utils.string_is_suffix CFrontend_config.autoreleasing_atribute objc_attribute
then Sil.Pk_objc_autoreleasing
else Sil.Pk_pointer in
Sil.Tptr (typ, (pointer_attribute_of_objc_attribute raw_type))
let rec return_type_of_function_type_ptr type_ptr =
let open Clang_ast_t in
try
let c_type = Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.pointer_type_index in
match c_type with
| FunctionProtoType (type_info, function_type_info, _)
| FunctionNoProtoType (type_info, function_type_info) ->
function_type_info.Clang_ast_t.fti_return_type
| BlockPointerType (type_info, in_type_ptr) ->
return_type_of_function_type_ptr in_type_ptr
| _ ->
Printing.log_err "Warning: Type pointer %s is not a function type."
(Clang_ast_j.string_of_pointer type_ptr);
""
with Not_found ->
Printing.log_err "Warning: Type pointer %s not found."
(Clang_ast_j.string_of_pointer type_ptr);
""
let return_type_of_function_type qt =
return_type_of_function_type_ptr qt.Clang_ast_t.qt_type_ptr
(* Expand a named type Tvar if it has a definition in tenv. This is used for Tenum, Tstruct, etc. *)
let rec expand_structured_type tenv typ =
match typ with
| Sil.Tvar tn ->
(match Sil.tenv_lookup tenv tn with
| Some t ->
Printing.log_out " Type expanded with type '%s' found in tenv@." (Sil.typ_to_string t);
if Sil.typ_equal t typ then
typ
else expand_structured_type tenv t
| None -> typ)
| Sil.Tptr(t, _) -> typ (*do not expand types under pointers *)
| _ -> typ
(* To be called with strings of format "<pointer_type_info>*<class_name>" *)
let get_name_from_type_pointer custom_type_pointer =
match Str.split (Str.regexp "*") custom_type_pointer with
| [pointer_type_info; class_name] -> pointer_type_info, class_name
| _ -> assert false

@ -27,6 +27,10 @@ val get_function_return_type : string -> string
val mk_classname : string -> Sil.typename val mk_classname : string -> Sil.typename
val mk_structname : string -> Sil.typename
val mk_enumname : string -> Sil.typename
val get_name_from_struct: Sil.typ -> Mangled.t val get_name_from_struct: Sil.typ -> Mangled.t
(* Remove the work 'struct' from a type name. Used to avoid repetition when typename are constructed*) (* Remove the work 'struct' from a type name. Used to avoid repetition when typename are constructed*)
@ -36,3 +40,11 @@ val cut_struct_union : string -> string
val remove_pointer_to_typ : Sil.typ -> Sil.typ val remove_pointer_to_typ : Sil.typ -> Sil.typ
val is_class : Sil.typ -> bool val is_class : Sil.typ -> bool
val sil_type_of_attr_pointer_type : Sil.typ -> string -> Sil.typ
val return_type_of_function_type : Clang_ast_t.qual_type -> Clang_ast_t.pointer
val expand_structured_type : Sil.tenv -> Sil.typ -> Sil.typ
val get_name_from_type_pointer : string -> string * string

@ -65,70 +65,7 @@ let rec search_for_named_type tenv typ =
Sil.Tptr (search_for_named_type tenv typ, p) Sil.Tptr (search_for_named_type tenv typ, p)
| _ -> typ | _ -> typ
(* Type representation is string in the clang ast. We use a parser for *) let parse_func_type name func_type = None
(* parsing and then translating the type The parser is higher-order and *)
(* takes a tenv as needs to do look-ups *)
let string_type_to_sil_type tenv s =
Printing.log_out " ...Trying parsing TYPE from string: '%s'@." s;
if s = "" then (
Printing.log_stats "\n Empty string parsed as type Void.\n";
Sil.Tvoid)
else (
(* NOTE sometimes we need to remove an extra occurrence of the word*)
(* "struct" or "union" used in RecordDecl raw type but not in VarDecl or other*)
(* raw types. This inconsistence gives problems when looking up tenv.*)
(* To overcome that we remove consistently this extra "union"/"struct" everytyme *)
(* we translate a type.*)
(* Example: 'union <anonymous union at union.c:4:1>' will be *)
(* 'union <anonymous at union.c:4:1>'*)
let s = (match Str.split (Str.regexp "[ \t]+") s with
| "struct"::"(anonymous":: "struct":: s' ->
(*Printing.log_out " ...Getting rid of the extra 'struct' word@."; *)
General_utils.string_from_list ("struct"::"(anonymous":: s')
| "union"::"(anonymous":: "union":: s' ->
(*Printing.log_out " ...Getting rid of the extra 'union' word@."; *)
General_utils.string_from_list ("union"::"(anonymous":: s')
| _ -> s) in
let lexbuf = Lexing.from_string s in
let t =
try
let t = CTypes_parser.parse (Ast_lexer.token) lexbuf in
Printing.log_out
" ...Parsed. Translated with sil TYPE '%a'@." (Sil.pp_typ_full pe_text) t;
t
with Parsing.Parse_error -> (
Printing.log_stats
"\nXXXXXXX PARSE ERROR for string '%s'. RETURNING Void.TODO@.@." s;
Sil.Tvoid) in
try
search_for_named_type tenv t
with Typename_not_found -> Printing.log_stats
"\nXXXXXX Parsed string '%s' as UNKNOWN type name. RETURNING a type name.TODO@.@." s;
t)
let qual_type_to_sil_type_no_expansions tenv qt =
string_type_to_sil_type tenv (CTypes.get_type qt)
let opt_type_to_sil_type tenv opt_type =
match opt_type with
| `Type(s) -> qual_type_to_sil_type_no_expansions tenv (Ast_expressions.create_qual_type s)
| `NoType -> Sil.Tvoid
let parse_func_type name func_type =
try
let lexbuf = Lexing.from_string func_type in
let (return_type, arg_types) = CTypes_parser.clang_func_type (Ast_lexer.token) lexbuf in
let arg_types =
match arg_types with
| [Sil.Tvoid] -> []
| _ -> arg_types in
Printing.log_out
" ...Parsed. Translated with sil return type '%s' @."
((Sil.typ_to_string return_type)^" <- "^(Utils.list_to_string (Sil.typ_to_string) arg_types));
Some (return_type, arg_types)
with Parsing.Parse_error -> (
Printing.log_stats "\nXXXXXXX PARSE ERROR for string '%s'." func_type;
None)
(* We need to take the name out of the type as the struct can be anonymous*) (* We need to take the name out of the type as the struct can be anonymous*)
@ -177,6 +114,11 @@ let rec disambiguate_typedef tenv namespace t mn =
else t else t
| _ -> t | _ -> t
and opt_type_to_sil_type tenv opt_type =
match opt_type with
| `Type(s) -> qual_type_to_sil_type tenv (Ast_expressions.create_qual_type s)
| `NoType -> Sil.Tvoid
and do_typedef_declaration tenv namespace decl_info name opt_type typedef_decl_info = and do_typedef_declaration tenv namespace decl_info name opt_type typedef_decl_info =
if name = CFrontend_config.class_type || name = CFrontend_config.id_cl then () if name = CFrontend_config.class_type || name = CFrontend_config.id_cl then ()
else else
@ -205,7 +147,7 @@ and get_struct_fields tenv record_name namespace decl_list =
[(id, typ, annotation_items)] [(id, typ, annotation_items)]
| CXXRecordDecl _ | RecordDecl _ -> | CXXRecordDecl _ | RecordDecl _ ->
(* C++/C Records treated in the same way*) (* C++/C Records treated in the same way*)
add_types_from_decl_to_tenv tenv namespace decl; [] ignore (add_types_from_decl_to_tenv tenv namespace decl); []
| _ -> [] in | _ -> [] in
list_flatten (list_map do_one_decl decl_list) list_flatten (list_map do_one_decl decl_list)
@ -223,7 +165,8 @@ and get_class_methods tenv class_name namespace decl_list =
and add_types_from_decl_to_tenv tenv namespace decl = and add_types_from_decl_to_tenv tenv namespace decl =
let typ = get_declaration_type tenv namespace decl in let typ = get_declaration_type tenv namespace decl in
let typ = expand_structured_type tenv typ in let typ = expand_structured_type tenv typ in
add_struct_to_tenv tenv typ add_struct_to_tenv tenv typ;
typ
(* For a record declaration it returns/constructs the type *) (* For a record declaration it returns/constructs the type *)
and get_declaration_type tenv namespace decl = and get_declaration_type tenv namespace decl =
@ -251,7 +194,7 @@ and get_declaration_type tenv namespace decl =
let non_static_fields = CFrontend_utils.General_utils.sort_fields non_static_fields in let non_static_fields = CFrontend_utils.General_utils.sort_fields non_static_fields in
let static_fields = [] in (* Warning for the moment we do not treat static field. *) let static_fields = [] in (* Warning for the moment we do not treat static field. *)
let typ = (match opt_type with let typ = (match opt_type with
| `Type s -> qual_type_to_sil_type_no_expansions tenv (Ast_expressions.create_qual_type s) | `Type s -> qual_type_to_sil_type tenv (Ast_expressions.create_qual_type s)
| _ -> assert false) in | _ -> assert false) in
let csu = (match typ with let csu = (match typ with
| Sil.Tvar (Sil.TN_csu (csu, _)) -> csu | Sil.Tvar (Sil.TN_csu (csu, _)) -> csu
@ -285,7 +228,7 @@ and add_late_defined_record tenv namespace typename =
Sil.typename_equal typename pot_union_type) && Sil.typename_equal typename pot_union_type) &&
record_decl_info.Clang_ast_t.rdi_is_complete_definition then ( record_decl_info.Clang_ast_t.rdi_is_complete_definition then (
Printing.log_out "!!!! Adding late-defined record '%s'\n" t; Printing.log_out "!!!! Adding late-defined record '%s'\n" t;
add_types_from_decl_to_tenv tenv namespace d; ignore (add_types_from_decl_to_tenv tenv namespace d);
true) true)
else scan decls' else scan decls'
| _ -> scan decls') | _ -> scan decls')
@ -356,23 +299,15 @@ and add_struct_to_tenv tenv typ =
| Some t -> Printing.log_out " >>>OK. Found typ='%s'\n" (Sil.typ_to_string t) | Some t -> Printing.log_out " >>>OK. Found typ='%s'\n" (Sil.typ_to_string t)
| None -> Printing.log_out " >>>NOT Found!!\n") | None -> Printing.log_out " >>>NOT Found!!\n")
and qual_type_to_sil_type_general tenv qt no_pointer = (* Translate a qual_type from clang to sil type. *)
let typ = string_type_to_sil_type tenv (CTypes.get_type qt) in
match typ with
| Sil.Tptr(np_typ, _) when no_pointer ->
expand_structured_type tenv np_typ
| _ -> expand_structured_type tenv typ
(* Translate a qual_type from clang to sil type. It uses the raw field *)
(* (rather than desugared) *)
and qual_type_to_sil_type tenv qt = and qual_type_to_sil_type tenv qt =
qual_type_to_sil_type_general tenv qt false CType_to_sil_type.qual_type_to_sil_type add_types_from_decl_to_tenv tenv qt
and qual_type_to_sil_type_np tenv qt = and qual_type_to_sil_type_np tenv qt =
qual_type_to_sil_type_general tenv qt true qual_type_to_sil_type tenv qt
and type_name_to_sil_type tenv name = and type_name_to_sil_type tenv name =
qual_type_to_sil_type_general tenv (Ast_expressions.create_qual_type name) false qual_type_to_sil_type tenv (Ast_expressions.create_qual_type name)
let get_type_from_expr_info ei tenv = let get_type_from_expr_info ei tenv =
let qt = ei.Clang_ast_t.ei_qual_type in let qt = ei.Clang_ast_t.ei_qual_type in

@ -20,7 +20,7 @@ val get_method_decls : Clang_ast_t.decl -> Clang_ast_t.decl list -> (Clang_ast_t
val do_typedef_declaration : Sil.tenv -> string option -> Clang_ast_t.decl_info -> string -> val do_typedef_declaration : Sil.tenv -> string option -> Clang_ast_t.decl_info -> string ->
Clang_ast_t.opt_type -> Clang_ast_t.typedef_decl_info -> unit Clang_ast_t.opt_type -> Clang_ast_t.typedef_decl_info -> unit
val add_types_from_decl_to_tenv : Sil.tenv -> string option -> Clang_ast_t.decl -> unit val add_types_from_decl_to_tenv : Sil.tenv -> string option -> Clang_ast_t.decl -> Sil.typ
val parse_func_type : string -> string -> (Sil.typ * Sil.typ list) option val parse_func_type : string -> string -> (Sil.typ * Sil.typ list) option

@ -1,239 +0,0 @@
/*
* Copyright (c) 2013 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
/* Parser for types in the ast of clang */
%{
%}
%token INLINE STATIC CONST STARCONST EXTERN VOID CHAR SHORT INT LONG FLOAT DOUBLE UND_BOOL VOLATILE STARVOLATILE CARRET
%token CLASS STRUCT UNION UND_UND_UINT16_ UND_UND_UINT16_T UND_UND_UINT32_ UND_UND_INT32_T UND_UND_UINT32_T
%token UND_UND_INT64_T UND_UND_UINT64_T UINT8 UINT16 UINT32 UINT64 UNSIGNED SIGNED ENUM BUILTIN_FN_TYPE TYPENAME
%token UND_UND_STRONG UND_UND_UNSAFE_RETAIN UND_UND_WEAK UND_UND_AUTORELEASING NOEXCEPT
%token STAR_UND_UND_STRONG STAR_UND_UND_UNSAFE_UNRETAINED UND_UND_UNSAFE_UNRETAINED STAR_UND_UND_WEAK STAR_UND_UND_AUTORELEASING
%token DOT SEMICOLON COLON COMMA SINGLE_QUOTE DOUBLE_QUOTE REV_QUOTE
%token PERCENT AMPERSAND EXCLAMATION EQUAL MINUS PLUS RESTRICT
%token LEFT_CHEVRON RIGHT_CHEVRON LEFT_PARENTHESIS RIGHT_PARENTHESIS LEFT_SQBRACKET RIGHT_SQBRACKET LEFT_BRACE RIGHT_BRACE
%token STAR PIPE SLASH BACKSLASH
%token <string> HEXA
%token <string> NUMBER
%token <string> IDENT
%token <string> ANONYM_IDENT
%token <string> NESTED_IDENT
%token <string> NESTED_ANONYM_IDENT
%token EOF
%start parse
%start pointer_clang_type
%start clang_func_type
%type <Sil.typ> pointer_clang_type
%type <Sil.typ> parse
%type <(Sil.typ * Sil.typ list)> clang_func_type
%%
keyword:
| ENUM { "enum" }
| UNSIGNED { "unsigned" }
| SIGNED { "signed" }
| CLASS { "class" }
| STRUCT { "struct" }
| UNION { "union" }
| VOID { "void" }
| CHAR { "char" }
| SHORT { "short" }
| INT { "int" }
| LONG { "long" }
| TYPENAME { "typename" }
| NOEXCEPT { "noexcept" }
| CONST { "const" }
| STARCONST { "*const" }
| FLOAT { "float" }
| DOUBLE { "double" }
| VOLATILE { "volatile" }
| RESTRICT { "restrict" }
| STARVOLATILE { "*volatile" }
ident:
| IDENT { $1 }
;
anonym_ident:
| ANONYM_IDENT { $1 }
;
nested_ident:
| NESTED_IDENT { $1 }
;
nested_anonym_ident:
| NESTED_ANONYM_IDENT { $1 }
;
ident_csu:
| ident {$1}
| anonym_ident { $1 }
| nested_ident { $1 }
| nested_anonym_ident { $1 }
identk:
| ident { $1 }
| keyword { $1 }
;
csu_sil:
| CLASS { Sil.Class }
| STRUCT { Sil.Struct }
| UNION { Sil.Union }
;
arc_qualifier:
| UND_UND_STRONG { Sil.Pk_pointer }
| UND_UND_UNSAFE_UNRETAINED { Sil.Pk_objc_unsafe_unretained }
| UND_UND_WEAK { Sil.Pk_objc_weak }
| UND_UND_AUTORELEASING { Sil.Pk_objc_autoreleasing }
;
star_arc_qualifier:
| STAR_UND_UND_STRONG { Sil.Pk_pointer }
| STAR_UND_UND_UNSAFE_UNRETAINED { Sil.Pk_objc_unsafe_unretained }
| STAR_UND_UND_WEAK { Sil.Pk_objc_weak }
| STAR_UND_UND_AUTORELEASING { Sil.Pk_objc_autoreleasing }
;
number_list:
| { [] }
| NUMBER { [$1] } /* For dealing with an unspecified number of arguments */
| NUMBER COMMA number_list { $1::$3 }
;
pointer_clang_type_list:
| { [] }
| DOT DOT DOT { [] } /* For dealing with an unspecified number of arguments */
| pointer_clang_type { [$1]}
| pointer_clang_type COMMA pointer_clang_type_list { $1::$3 }
;
array_index:
| LEFT_SQBRACKET NUMBER RIGHT_SQBRACKET { Sil.Const (Sil.Cint((Sil.int_of_int64_kind (Int64.of_string $2) (Sil.IInt)))) }
;
block_type:
| pointer_clang_type LEFT_PARENTHESIS CARRET RIGHT_PARENTHESIS
LEFT_PARENTHESIS pointer_clang_type_list RIGHT_PARENTHESIS
{ Sil.Tfun false }
| pointer_clang_type LEFT_PARENTHESIS CARRET arc_qualifier RIGHT_PARENTHESIS
LEFT_PARENTHESIS pointer_clang_type_list RIGHT_PARENTHESIS
{ Sil.Tfun false }
| pointer_clang_type LEFT_PARENTHESIS CARRET CONST arc_qualifier RIGHT_PARENTHESIS
LEFT_PARENTHESIS pointer_clang_type_list RIGHT_PARENTHESIS
{ Sil.Tfun false }
| pointer_clang_type LEFT_PARENTHESIS CARRET CONST RIGHT_PARENTHESIS
LEFT_PARENTHESIS pointer_clang_type_list RIGHT_PARENTHESIS
{ Sil.Tfun false }
;
array_qualifier:
| CONST {}
| arc_qualifier {} /* Currently array do not deal with arc qualifiers */
;
template:
| LEFT_CHEVRON pointer_clang_type_list RIGHT_CHEVRON {}
| LEFT_CHEVRON number_list RIGHT_CHEVRON {}
;
/* Nested arrays must be translated inside-out. */
array_indices:
| array_index { [$1] }
| array_index array_indices { $1 :: $2 }
pointer_clang_type:
| pointer_clang_type array_indices { List.fold_left (fun t x -> Sil.Tarray (t, x)) $1 (List.rev $2) }
| pointer_clang_type LEFT_SQBRACKET RIGHT_SQBRACKET { Sil.Tptr($1, Sil.Pk_pointer) }
| pointer_clang_type STAR { Sil.Tptr($1, Sil.Pk_pointer) }
| pointer_clang_type AMPERSAND { Sil.Tptr($1, Sil.Pk_reference) }
| pointer_clang_type STARCONST arc_qualifier { Sil.Tptr($1, $3) }
| arc_qualifier pointer_clang_type { Sil.Tptr($2,$1) }
| pointer_clang_type STARCONST { Sil.Tptr($1, Sil.Pk_pointer) }
| pointer_clang_type STARVOLATILE { Sil.Tptr($1, Sil.Pk_pointer) }
| pointer_clang_type STAR RESTRICT { Sil.Tptr($1, Sil.Pk_pointer) }
| pointer_clang_type star_arc_qualifier { Sil.Tptr($1, $2) }
| clang_type { $1 }
| clang_type array_qualifier array_indices { List.fold_left (fun t x -> Sil.Tarray (t, x)) $1 (List.rev $3) }
| clang_type template { $1 }
| pointer_clang_type LEFT_PARENTHESIS STAR RIGHT_PARENTHESIS
LEFT_PARENTHESIS pointer_clang_type_list RIGHT_PARENTHESIS
{ Sil.Tptr(Sil.Tfun false, Sil.Pk_pointer) }
| pointer_clang_type LEFT_PARENTHESIS STAR RIGHT_PARENTHESIS
LEFT_PARENTHESIS pointer_clang_type_list RIGHT_PARENTHESIS NOEXCEPT
{ Sil.Tptr(Sil.Tfun false, Sil.Pk_pointer) }
| block_type { Sil.Tptr($1, Sil.Pk_pointer) }
| pointer_clang_type LEFT_PARENTHESIS pointer_clang_type_list RIGHT_PARENTHESIS
{ CFrontend_utils.Printing.log_err "WARNING: PARSING with TFun!\n";
Sil.Tfun false }
;
clang_type:
| UND_UND_UINT16_ { Sil.Tint Sil.IUInt }
| UND_UND_UINT16_T { Sil.Tint Sil.IUInt }
| UND_UND_UINT32_ { Sil.Tint Sil.IUInt }
| UND_UND_UINT32_T { Sil.Tint Sil.IUInt }
| UND_UND_UINT64_T { Sil.Tint Sil.IUInt }
| UND_UND_INT64_T { Sil.Tint Sil.IInt }
| UND_UND_INT32_T { Sil.Tint Sil.IInt }
| UINT8 { Sil.Tint Sil.IUInt }
| UINT16 { Sil.Tint Sil.IUInt }
| UINT32 { Sil.Tint Sil.IUInt }
| UINT64 { Sil.Tint Sil.IUInt }
| UNSIGNED INT { Sil.Tint Sil.IUInt }
| UNSIGNED LONG LONG { Sil.Tint Sil.IULongLong }
| UNSIGNED LONG { Sil.Tint Sil.IULong }
| UNSIGNED SHORT { Sil.Tint Sil.IUShort }
| FLOAT { Sil.Tfloat Sil.FFloat }
| DOUBLE { Sil.Tfloat Sil.FDouble }
| VOID { Sil.Tvoid }
| CHAR { Sil.Tint Sil.IChar }
| SIGNED CHAR { Sil.Tint Sil.ISChar }
| UNSIGNED CHAR { Sil.Tint Sil.IUChar }
| INT { Sil.Tint Sil.IInt }
| UND_BOOL { Sil.Tint Sil.IBool }
| SHORT { Sil.Tint Sil.IShort }
| LONG { Sil.Tint Sil.ILong }
| LONG LONG { Sil.Tint Sil.ILongLong }
| LONG DOUBLE { Sil.Tfloat Sil.FLongDouble }
| ENUM ident {Sil.Tvar (Sil.TN_enum (Mangled.from_string ("enum "^$2))) }
| BUILTIN_FN_TYPE { CFrontend_utils.Printing.log_err "WARNING: Parsing this with Tfun!\n";
Sil.Tfun false }
| CONST pointer_clang_type { $2 }
| CONST TYPENAME pointer_clang_type { $3 }
| VOLATILE pointer_clang_type { $2 }
| ident ANONYM_IDENT { CFrontend_utils.Printing.log_out " ...Found just an identifier modified with a protocol. Ignoring protocol!. Parsing as Named Type!\n";
Sil.Tvar (Sil.TN_typedef(Mangled.from_string $1))}
| ident { Sil.Tvar (Sil.TN_typedef(Mangled.from_string $1))}
| csu_sil ident_csu { let typename=Sil.TN_csu($1, Mangled.from_string $2) in
Sil.Tvar typename }
;
clang_type_list:
| clang_type COMMA clang_type_list {$1 :: $3}
| clang_type {[$1]}
clang_func_type:
| clang_type LEFT_PARENTHESIS clang_type_list RIGHT_PARENTHESIS
{($1, $3)}
parse:
| pointer_clang_type { $1 }
Loading…
Cancel
Save