From 8e547d197dde352787696c11ccfa3a362c3aa9a0 Mon Sep 17 00:00:00 2001 From: Dulma Rodriguez Date: Tue, 15 Sep 2015 09:16:35 -0100 Subject: [PATCH] [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. --- infer/src/clang/ast_lexer.mll | 146 ---------------- infer/src/clang/cFrontend.ml | 2 +- infer/src/clang/cFrontend_config.ml | 12 ++ infer/src/clang/cFrontend_config.mli | 12 ++ infer/src/clang/cFrontend_utils.ml | 4 + infer/src/clang/cFrontend_utils.mli | 2 + infer/src/clang/cMain.ml | 3 +- infer/src/clang/cType_to_sil_type.ml | 169 ++++++++++++++++++ infer/src/clang/cType_to_sil_type.mli | 17 ++ infer/src/clang/cTypes.ml | 62 ++++++- infer/src/clang/cTypes.mli | 12 ++ infer/src/clang/cTypes_decl.ml | 95 ++-------- infer/src/clang/cTypes_decl.mli | 2 +- infer/src/clang/cTypes_parser.mly | 239 -------------------------- 14 files changed, 307 insertions(+), 470 deletions(-) delete mode 100644 infer/src/clang/ast_lexer.mll create mode 100644 infer/src/clang/cType_to_sil_type.ml create mode 100644 infer/src/clang/cType_to_sil_type.mli delete mode 100644 infer/src/clang/cTypes_parser.mly diff --git a/infer/src/clang/ast_lexer.mll b/infer/src/clang/ast_lexer.mll deleted file mode 100644 index bd659fdb5..000000000 --- a/infer/src/clang/ast_lexer.mll +++ /dev/null @@ -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 } - | "" { 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 } - diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index bf944352a..1972dec31 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -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 *) | CXXRecordDecl (_, _, _, _, 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 tranlate_method (parent, decl) = translate_one_declaration tenv cg cfg namespace parent decl in diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index b9b9d14fb..350fcb6d0 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -149,3 +149,15 @@ let ns_array_ptr = "NSArray *" let enumerateObjectsUsingBlock = "enumerateObjectsUsingBlock:" 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" diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index f8038119a..99ab3e6d4 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -146,3 +146,15 @@ val ns_array_ptr : string val enumerateObjectsUsingBlock : 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 diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index 3020b8b9c..0638cdd63 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -263,6 +263,10 @@ struct 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 + 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 (* Global counter for anonymous block*) diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index 2146195e4..dd42c5368 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -77,6 +77,8 @@ sig 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 module General_utils : diff --git a/infer/src/clang/cMain.ml b/infer/src/clang/cMain.ml index dd1d8e28f..acb1e0f32 100644 --- a/infer/src/clang/cMain.ml +++ b/infer/src/clang/cMain.ml @@ -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 "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_type_index := type_index; CFrontend_config.json := ast_filename; CLocation.check_source_file source_path; let source_file = CLocation.source_file_from_path source_path in diff --git a/infer/src/clang/cType_to_sil_type.ml b/infer/src/clang/cType_to_sil_type.ml new file mode 100644 index 000000000..f8ffc2503 --- /dev/null +++ b/infer/src/clang/cType_to_sil_type.ml @@ -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 diff --git a/infer/src/clang/cType_to_sil_type.mli b/infer/src/clang/cType_to_sil_type.mli new file mode 100644 index 000000000..77c543eb3 --- /dev/null +++ b/infer/src/clang/cType_to_sil_type.mli @@ -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 diff --git a/infer/src/clang/cTypes.ml b/infer/src/clang/cTypes.ml index 478e27982..051c34d77 100644 --- a/infer/src/clang/cTypes.ml +++ b/infer/src/clang/cTypes.ml @@ -195,8 +195,11 @@ let search_enum_type_by_name tenv name = Sil.tenv_iter f tenv; !found -let mk_classname n = - Sil.TN_csu (Sil.Class, Mangled.from_string n) +let mk_classname 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 = match typ with @@ -204,3 +207,58 @@ let is_class typ = | Sil.Tptr( Sil.Tvar (Sil.TN_csu (_, name) ), _) -> (Mangled.to_string name) = CFrontend_config.objc_class | _ -> 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 "*" *) +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 diff --git a/infer/src/clang/cTypes.mli b/infer/src/clang/cTypes.mli index 46f5e23dd..fdea7c2d6 100644 --- a/infer/src/clang/cTypes.mli +++ b/infer/src/clang/cTypes.mli @@ -27,6 +27,10 @@ val get_function_return_type : string -> string 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 (* 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 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 diff --git a/infer/src/clang/cTypes_decl.ml b/infer/src/clang/cTypes_decl.ml index 593c33809..8306d0878 100644 --- a/infer/src/clang/cTypes_decl.ml +++ b/infer/src/clang/cTypes_decl.ml @@ -65,70 +65,7 @@ let rec search_for_named_type tenv typ = Sil.Tptr (search_for_named_type tenv typ, p) | _ -> typ -(* Type representation is string in the clang ast. We use a parser for *) -(* 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 ' will be *) - (* 'union '*) - 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) +let parse_func_type name func_type = None (* 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 | _ -> 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 = if name = CFrontend_config.class_type || name = CFrontend_config.id_cl then () else @@ -205,7 +147,7 @@ and get_struct_fields tenv record_name namespace decl_list = [(id, typ, annotation_items)] | CXXRecordDecl _ | RecordDecl _ -> (* 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 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 = let typ = get_declaration_type tenv namespace decl 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 *) 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 static_fields = [] in (* Warning for the moment we do not treat static field. *) 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 let csu = (match typ with | 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) && record_decl_info.Clang_ast_t.rdi_is_complete_definition then ( 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) else 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) | None -> Printing.log_out " >>>NOT Found!!\n") -and qual_type_to_sil_type_general tenv qt no_pointer = - 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) *) +(* Translate a qual_type from clang to sil type. *) 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 = - qual_type_to_sil_type_general tenv qt true + qual_type_to_sil_type tenv qt 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 qt = ei.Clang_ast_t.ei_qual_type in diff --git a/infer/src/clang/cTypes_decl.mli b/infer/src/clang/cTypes_decl.mli index 17ae05cd1..47b2c1ef6 100644 --- a/infer/src/clang/cTypes_decl.mli +++ b/infer/src/clang/cTypes_decl.mli @@ -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 -> 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 diff --git a/infer/src/clang/cTypes_parser.mly b/infer/src/clang/cTypes_parser.mly deleted file mode 100644 index d50dc2441..000000000 --- a/infer/src/clang/cTypes_parser.mly +++ /dev/null @@ -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 HEXA -%token NUMBER -%token IDENT -%token ANONYM_IDENT -%token NESTED_IDENT -%token NESTED_ANONYM_IDENT - -%token EOF - -%start parse -%start pointer_clang_type -%start clang_func_type - -%type pointer_clang_type -%type 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 }