(* * 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. *) (** Translate an enumeration declaration by adding it to the tenv and *) (** translating the code and adding it to a fake procdesc *) open CFrontend_utils open Clang_ast_t let create_empty_procdesc () = let procname = Procname.from_string_c_fun "__INFER_$GLOBAL_VAR_env" in let open Cfg.Procdesc in let proc_attributes = { Sil.access = Sil.Default; Sil.exceptions = []; Sil.is_abstract = false; Sil.is_bridge_method = false; Sil.is_objc_instance_method = false; Sil.is_synthetic_method = false; Sil.language = Sil.C_CPP; Sil.func_attributes = []; Sil.method_annotation = Sil.method_annotation_empty; Sil.is_generated = false; } in create { cfg = Cfg.Node.create_cfg (); name = procname; is_defined = false; ret_type = Sil.Tvoid; formals = []; locals = []; captured = []; loc = Sil.loc_none; proc_attributes = proc_attributes; } (* We will use global_procdesc for storing global variables. *) (* Globals will be stored as locals in global_procdesc and they are added*) (* when traversing the AST. *) let global_procdesc = ref (create_empty_procdesc ()) let rec get_enum_constants context decl_list v = match decl_list with | [] -> [] | EnumConstantDecl(decl_info, name_info, qual_type, enum_constant_decl_info) :: decl_list' -> let name = name_info.Clang_ast_t.ni_name in (match enum_constant_decl_info.Clang_ast_t.ecdi_init_expr with | None -> Printing.log_out "%s" (" ...Defining Enum Constant ("^name^", "^(string_of_int v)); (Mangled.from_string name, Sil.Cint (Sil.Int.of_int v)) :: get_enum_constants context decl_list' (v + 1) | Some stmt -> let e = CGen_trans.CTransImpl.expression_trans context stmt "WARNING: Expression in Enumeration constant not found\n" in let const = (match Prop.exp_normalize_prop Prop.prop_emp e with | Sil.Const c -> c | _ -> (* This is a hack to avoid failing in some strange definition of Enum *) Sil.Cint Sil.Int.zero) in Printing.log_out " ...Defining Enum Constant ('%s', " name; Printing.log_out "'%s')\n" (Sil.exp_to_string (Sil.Const const)); (Mangled.from_string name, const) :: get_enum_constants context decl_list' v) | _ -> assert false let enum_decl name tenv cfg cg namespace decl_list opt_type = Printing.log_out "ADDING: EnumDecl '%s'\n" name; let context' = CContext.create_context tenv cg cfg !global_procdesc namespace CContext.ContextNoCls false [] false in let enum_constants = get_enum_constants context' decl_list 0 in let name = (match opt_type with (* If the type is defined it's of the kind "enum name" and we take that.*) | `Type s -> s | `NoType -> assert false) in (* Here we could give "enum "^name but I want to check that this the type is always defined *) let typename = Sil.TN_enum (Mangled.from_string name) in let typ = Sil.Tenum enum_constants in Printing.log_out " TN_typename('%s')\n" (Sil.typename_to_string typename); Sil.tenv_add tenv typename typ