Summary: This diff introduces a first version of a front-end checkers specification language. The language is based on the CTL temporal logic that is interpreted on trees. In this case the model for a formula is the AST of the program produced by clang. This diff introduce the language and translate most of the existing checks on this new language. In other diff I will translate all the other checks. Then I will generalize the framework to allow the developer to specify only the CTL formula. Reviewed By: martinoluca Differential Revision: D3819211 fbshipit-source-id: f8e01ebmaster
parent
fc28683ea2
commit
05bb4a0db7
@ -0,0 +1,317 @@
|
||||
(*
|
||||
* Copyright (c) 2016 - 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! Utils
|
||||
|
||||
open CFrontend_utils
|
||||
|
||||
(* This module defines a language to define checkers. These checkers
|
||||
are intepreted over the AST of the program. A checker is defined by a
|
||||
CTL formula which express a condition saying when the checker should
|
||||
report a problem *)
|
||||
|
||||
|
||||
(* Label that allows switching from a decl node to a stmt node *)
|
||||
type transition_decl_to_stmt =
|
||||
| Body
|
||||
| InitExpr
|
||||
|
||||
(* In formulas below prefix
|
||||
"E" means "exists a path"
|
||||
"A" means "for all path" *)
|
||||
|
||||
type t = (* A ctl formula *)
|
||||
| True
|
||||
| False (* not really necessary but it makes it evaluation faster *)
|
||||
| Atomic of Predicates.t
|
||||
| Not of t
|
||||
| And of t * t
|
||||
| Or of t * t
|
||||
| Implies of t * t
|
||||
| AX of t
|
||||
| EX of t
|
||||
| AF of t
|
||||
| EF of t
|
||||
| AG of t
|
||||
| EG of t
|
||||
| AU of t * t
|
||||
| EU of t * t
|
||||
| EH of string list * t
|
||||
| ET of string list * transition_decl_to_stmt option * t
|
||||
|
||||
(* the kind of AST nodes where formulas are evaluated *)
|
||||
type ast_node =
|
||||
| Stmt of Clang_ast_t.stmt
|
||||
| Decl of Clang_ast_t.decl
|
||||
|
||||
|
||||
(* Helper functions *)
|
||||
|
||||
(* true iff an ast node is a node of type among the list tl *)
|
||||
let node_has_type tl an =
|
||||
let an_str = match an with
|
||||
| Decl d -> Clang_ast_proj.get_decl_kind_string d
|
||||
| Stmt s -> Clang_ast_proj.get_stmt_kind_string s in
|
||||
IList.mem (string_equal) an_str tl
|
||||
|
||||
(* given a decl returns a stmt such that decl--->stmt via label trs *)
|
||||
let transition_from_decl_to_stmt d trs =
|
||||
let open Clang_ast_t in
|
||||
match trs, d with
|
||||
| Some Body, ObjCMethodDecl (_, _, omdi) -> omdi.omdi_body
|
||||
| Some Body, FunctionDecl (_, _, _, fdi)
|
||||
| Some Body, CXXMethodDecl (_, _, _, fdi,_ )
|
||||
| Some Body, CXXConstructorDecl (_, _, _, fdi, _)
|
||||
| Some Body, CXXConversionDecl (_, _, _, fdi, _)
|
||||
| Some Body, CXXDestructorDecl (_, _, _, fdi, _) -> fdi.fdi_body
|
||||
| Some Body, BlockDecl (_, bdi) -> bdi.bdi_body
|
||||
| Some InitExpr, VarDecl (_, _ ,_, vdi) -> vdi.vdi_init_expr
|
||||
| Some InitExpr, ObjCIvarDecl (_, _, _, fldi, _)
|
||||
| Some InitExpr, FieldDecl (_, _, _, fldi)
|
||||
| Some InitExpr, ObjCAtDefsFieldDecl (_, _, _, fldi)-> fldi.fldi_init_expr
|
||||
| Some InitExpr, CXXMethodDecl _
|
||||
| Some InitExpr, CXXConstructorDecl _
|
||||
| Some InitExpr, CXXConversionDecl _
|
||||
| Some InitExpr, CXXDestructorDecl _ ->
|
||||
assert false (* to be done. Requires extending to lists *)
|
||||
| Some InitExpr, EnumConstantDecl (_, _, _, ecdi) -> ecdi.ecdi_init_expr
|
||||
| _, _ -> None
|
||||
|
||||
(* given a stmt returns a decl such that stmt--->decl via label trs
|
||||
NOTE: for the moment we don't have any transitions stmt to decl as
|
||||
we don't have much experience.
|
||||
TBD: the list need to be populated when we know what we need *)
|
||||
let transition_from_stmt_to_decl st trs =
|
||||
match trs, st with
|
||||
| _, _ -> None (* For the moment always no transitions. TBD add transitions *)
|
||||
|
||||
|
||||
(* Evaluation of formulas *)
|
||||
|
||||
(* evaluate an atomic formula (i.e. a predicate) on a ast node an and a
|
||||
linter context lcxt. That is: an, lcxt |= pred_name(params) *)
|
||||
let eval_Atomic pred_name params an lcxt =
|
||||
match pred_name, params, an with
|
||||
| "call_method", [p1], Stmt st -> Predicates.call_method p1 st
|
||||
| "property_name_contains_word", [p1] , Decl d -> Predicates.property_name_contains_word d p1
|
||||
| "is_objc_extension", [], _ -> Predicates.is_objc_extension
|
||||
| "is_global_var", [], Decl d -> Predicates.is_syntactically_global_var d
|
||||
| "is_const_var", [], Decl d -> Predicates.is_const_expr_var d
|
||||
| "call_function_named", _, Stmt st -> Predicates.call_function_named st params
|
||||
| "is_statement_kind", [p1], Stmt st -> Predicates.is_statement_kind st p1
|
||||
| "is_declaration_kind", [p1], Decl d -> Predicates.is_declaration_kind d p1
|
||||
| "is_strong_property", [], Decl d -> Predicates.is_strong_property d
|
||||
| "is_assign_property", [], Decl d -> Predicates.is_assign_property d
|
||||
| "is_property_pointer_type", [], Decl d -> Predicates.is_property_pointer_type d
|
||||
| "context_in_synchronized_block", [], _ -> Predicates.context_in_synchronized_block lcxt
|
||||
| "is_ivar_atomic", [], Stmt st -> Predicates.is_ivar_atomic st
|
||||
| "is_method_property_accessor_of_ivar", [], Stmt st ->
|
||||
Predicates.is_method_property_accessor_of_ivar st lcxt
|
||||
| "is_objc_constructor", [], _ -> Predicates.is_objc_constructor lcxt
|
||||
| "is_objc_dealloc", [], _ -> Predicates.is_objc_dealloc lcxt
|
||||
| "captures_cxx_references", [], Stmt st -> Predicates.captures_cxx_references st
|
||||
| _ -> failwith ("ERROR: Undefined Predicate: "^pred_name)
|
||||
|
||||
(* st, lcxt |= EF phi <=>
|
||||
st, lcxt |= phi or exists st' in Successors(st): st', lcxt |= EF phi
|
||||
|
||||
That is: a (st, lcxt) satifies EF phi if and only if
|
||||
either (st,lcxt) satifies phi or there is a child st' of the node st
|
||||
such that (st', lcxt) satifies EF phi
|
||||
*)
|
||||
let rec eval_EF_st phi st lcxt =
|
||||
Printing.log_out "\n->>>> Evaluating EF in %s\n"
|
||||
(Clang_ast_proj.get_stmt_kind_string st);
|
||||
let _, succs = Clang_ast_proj.get_stmt_tuple st in
|
||||
(eval_formula phi (Stmt st) lcxt) ||
|
||||
IList.exists (fun s -> eval_EF phi (Stmt s) lcxt) succs
|
||||
|
||||
(* dec, lcxt |= EF phi <=>
|
||||
dec, lcxt |= phi or exists dec' in Successors(dec): dec', lcxt |= EF phi
|
||||
|
||||
This is as eval_EF_st but for decl.
|
||||
*)
|
||||
and eval_EF_decl phi dec lcxt =
|
||||
Printing.log_out "\n->>>> Evaluating EF in %s\n"
|
||||
(Clang_ast_proj.get_decl_kind_string dec);
|
||||
(eval_formula phi (Decl dec) lcxt) ||
|
||||
(match Clang_ast_proj.get_decl_context_tuple dec with
|
||||
| Some (decl_list, _) ->
|
||||
IList.exists (fun d -> eval_EF phi (Decl d) lcxt) decl_list
|
||||
| None -> false)
|
||||
|
||||
(* an, lcxt |= EF phi evaluates on decl or stmt depending on an *)
|
||||
and eval_EF phi an lcxt =
|
||||
match an with
|
||||
| Stmt st -> eval_EF_st phi st lcxt
|
||||
| Decl dec -> eval_EF_decl phi dec lcxt
|
||||
|
||||
(* st, lcxt |= EX phi <=> exists st' in Successors(st): st', lcxt |= phi
|
||||
|
||||
That is: a (st, lcxt) satifies EX phi if and only if
|
||||
there exists is a child st' of the node st
|
||||
such that (st', lcxt) satifies phi
|
||||
*)
|
||||
and eval_EX_st phi st lcxt =
|
||||
Printing.log_out "\n->>>> Evaluating EX in %s\n"
|
||||
(Clang_ast_proj.get_stmt_kind_string st);
|
||||
let _, succs = Clang_ast_proj.get_stmt_tuple st in
|
||||
IList.exists (fun s -> eval_formula phi (Stmt s) lcxt) succs
|
||||
|
||||
(* dec, lcxt |= EX phi <=> exists dec' in Successors(dec): dec',lcxt|= phi
|
||||
|
||||
Same as eval_EX_st but for decl.
|
||||
*)
|
||||
and eval_EX_decl phi dec lcxt =
|
||||
Printing.log_out "\n->>>> Evaluating EF in %s\n"
|
||||
(Clang_ast_proj.get_decl_kind_string dec);
|
||||
match Clang_ast_proj.get_decl_context_tuple dec with
|
||||
| Some (decl_list, _) ->
|
||||
IList.exists (fun d -> eval_formula phi (Decl d) lcxt) decl_list
|
||||
| None -> false
|
||||
|
||||
(* an |= EX phi evaluates on decl/stmt depending on the ast_node an *)
|
||||
and eval_EX phi an lcxt =
|
||||
match an with
|
||||
| Stmt st -> eval_EX_st phi st lcxt
|
||||
| Decl decl -> eval_EX_decl phi decl lcxt
|
||||
|
||||
(* an, lcxt |= E(phi1 U phi2) evaluated using the equivalence
|
||||
an, lcxt |= E(phi1 U phi2) <=> an, lcxt |= phi2 or (phi1 and EX(E(phi1 U phi2)))
|
||||
|
||||
That is: a (an,lcxt) satifies E(phi1 U phi2) if and only if
|
||||
an,lcxt satifies the formula phi2 or (phi1 and EX(E(phi1 U phi2)))
|
||||
*)
|
||||
and eval_EU phi1 phi2 an lcxt =
|
||||
let f = Or (phi2, And (phi1, EX (EU (phi1, phi2)))) in
|
||||
eval_formula f an lcxt
|
||||
|
||||
(* an |= A(phi1 U phi2) evaluated using the equivalence
|
||||
an |= A(phi1 U phi2) <=> an |= phi2 or (phi1 and AX(A(phi1 U phi2)))
|
||||
|
||||
Same as EU but for the all path quantifier A
|
||||
*)
|
||||
and eval_AU phi1 phi2 an lcxt =
|
||||
let f = Or (phi2, And (phi1, AX (AU (phi1, phi2)))) in
|
||||
eval_formula f an lcxt
|
||||
|
||||
(* Intuitive meaning: (an,lcxt) satifies EH[Classes] phi
|
||||
if the node an is among the declaration specified by the list Classes and
|
||||
there exists a super class in its hierarchy whose declaration satisfy phi.
|
||||
|
||||
an, lcxt |= EH[Classes] phi <=>
|
||||
the node an is in Classes and there exists a declaration d in Hierarchy(an)
|
||||
such that d,lcxt |= phi *)
|
||||
and eval_EH classes phi an lcxt =
|
||||
let rec eval_super impl_decl_info =
|
||||
match impl_decl_info with
|
||||
| Some idi ->
|
||||
(match Ast_utils.get_super_ObjCImplementationDecl idi with
|
||||
| Some (Clang_ast_t.ObjCImplementationDecl(_, _, _, _, idi') as d) ->
|
||||
eval_formula phi (Decl d) lcxt
|
||||
|| (eval_super (Some idi'))
|
||||
| _ -> false)
|
||||
| None -> false in
|
||||
match an with
|
||||
| Decl d when node_has_type classes (Decl d) ->
|
||||
Printing.log_out "\n->>>> Evaluating EH in %s\n"
|
||||
(Clang_ast_proj.get_decl_kind_string d);
|
||||
eval_super (Ast_utils.get_impl_decl_info d)
|
||||
| _ -> false
|
||||
|
||||
(* an, lcxt |= ET[T][->l]phi <=>
|
||||
an is a node among those defined in T and an-l->an'
|
||||
("an transitions" to another node an' via an edge labelled l)
|
||||
such that an',lcxt |= phi
|
||||
|
||||
or an is a node among those defined in T, and l is unspecified,
|
||||
and an,lcxt |= EF phi
|
||||
|
||||
or an is not of type in T and exists an' in Successors(an):
|
||||
an', lcxt |= ET[T][->l]phi
|
||||
*)
|
||||
and eval_ET tl trs phi an lcxt =
|
||||
let open Clang_ast_t in
|
||||
let evaluate_on_subdeclarations d eval =
|
||||
match Clang_ast_proj.get_decl_context_tuple d with
|
||||
| None -> false
|
||||
| Some (decl_list, _) ->
|
||||
IList.exists (fun d' -> eval phi (Decl d') lcxt) decl_list in
|
||||
let evaluate_on_substmt st eval =
|
||||
let _, stmt_list = Clang_ast_proj.get_stmt_tuple st in
|
||||
IList.exists (fun s -> eval phi (Stmt s) lcxt) stmt_list in
|
||||
let do_decl d =
|
||||
Printing.log_out "\n->>>> Evaluating ET in %s\n"
|
||||
(Clang_ast_proj.get_decl_kind_string d);
|
||||
match trs, node_has_type tl (Decl d) with
|
||||
| Some _, true ->
|
||||
Printing.log_out "\n ->>>> Declaration is in types and has label";
|
||||
(match transition_from_decl_to_stmt d trs with
|
||||
| None ->
|
||||
Printing.log_out "\n ->>>> NO transition returned";
|
||||
false
|
||||
| Some st ->
|
||||
Printing.log_out "\n ->>>> A transition is returned \n";
|
||||
eval_formula phi (Stmt st) lcxt)
|
||||
| None, true ->
|
||||
Printing.log_out "\n ->>>> Declaration has NO transition label\n";
|
||||
eval_EF_decl phi d lcxt
|
||||
| _, false ->
|
||||
Printing.log_out "\n ->>>> Declaration is NOT in types and _ label\n";
|
||||
evaluate_on_subdeclarations d (eval_ET tl trs) in
|
||||
let do_stmt st =
|
||||
Printing.log_out "\n->>>> Evaluating ET in %s\n"
|
||||
(Clang_ast_proj.get_stmt_kind_string st);
|
||||
match trs, node_has_type tl (Stmt st) with
|
||||
| Some _, true ->
|
||||
Printing.log_out "\n ->>>> Statement is in types and has label";
|
||||
(match transition_from_stmt_to_decl st trs with
|
||||
| None ->
|
||||
Printing.log_out "\n ->>>> NO transition returned\n";
|
||||
false
|
||||
| Some d ->
|
||||
Printing.log_out "\n ->>>> A transition is returned \n";
|
||||
eval_formula phi (Decl d) lcxt)
|
||||
| None, true ->
|
||||
Printing.log_out "\n ->>>> Statement has NO transition label\n";
|
||||
eval_EF_st phi st lcxt
|
||||
| _, false ->
|
||||
Printing.log_out "\n ->>>> Declaration is NOT in types and _ label\n";
|
||||
evaluate_on_substmt st (eval_ET tl trs) in
|
||||
match an with
|
||||
| Decl d -> do_decl d
|
||||
| Stmt BlockExpr(_, _, _, d) ->
|
||||
(* From BlockExpr we jump directly to its BlockDecl *)
|
||||
Printing.log_out "\n->>>> BlockExpr evaluated in ET, evaluating its BlockDecl \n";
|
||||
eval_ET tl trs phi (Decl d) lcxt
|
||||
| Stmt st -> do_stmt st
|
||||
|
||||
|
||||
(* Formulas are evaluated on a AST node an and a linter context lcxt *)
|
||||
and eval_formula f an lcxt =
|
||||
match f with
|
||||
| True -> true
|
||||
| False -> false
|
||||
| Atomic (name, params) -> eval_Atomic name params an lcxt
|
||||
| Not f1 -> not (eval_formula f1 an lcxt)
|
||||
| And (f1, f2) -> (eval_formula f1 an lcxt) && (eval_formula f2 an lcxt)
|
||||
| Or (f1, f2) -> (eval_formula f1 an lcxt) || (eval_formula f2 an lcxt)
|
||||
| Implies (f1, f2) ->
|
||||
not (eval_formula f1 an lcxt) || (eval_formula f2 an lcxt)
|
||||
| AU (f1, f2) -> eval_AU f1 f2 an lcxt
|
||||
| EU (f1, f2) -> eval_EU f1 f2 an lcxt
|
||||
| EF f1 -> eval_EF f1 an lcxt
|
||||
| AF f1 -> eval_formula (AU (True, f1)) an lcxt
|
||||
| AG f1 -> eval_formula (Not (EF (Not f1))) an lcxt
|
||||
| EX f1 -> eval_EX f1 an lcxt
|
||||
| AX f1 -> eval_formula (Not (EX (Not f1))) an lcxt
|
||||
| EH (cl, phi) -> eval_EH cl phi an lcxt
|
||||
| EG f1 -> (* st |= EG f1 <=> st |= f1 /\ EX EG f1 *)
|
||||
eval_formula (And (f1, EX (EG (f1)))) an lcxt
|
||||
| ET (tl, sw, phi) -> eval_ET tl sw phi an lcxt
|
@ -0,0 +1,56 @@
|
||||
(*
|
||||
* Copyright (c) 2016 - 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.
|
||||
*)
|
||||
|
||||
(* This module defines a language to define checkers. These checkers
|
||||
are intepreted over the AST of the program. A checker is defined by a
|
||||
CTL formula which express a condition saying when the checker should
|
||||
report a problem *)
|
||||
|
||||
type transition_decl_to_stmt =
|
||||
| Body
|
||||
| InitExpr
|
||||
|
||||
|
||||
(* In formulas below prefix
|
||||
"E" means "exists a path"
|
||||
"A" means "for all path" *)
|
||||
|
||||
(** A ctl formula *)
|
||||
type t =
|
||||
| True
|
||||
| False
|
||||
| Atomic of Predicates.t (** Atomic formula *)
|
||||
| Not of t
|
||||
| And of t * t
|
||||
| Or of t * t
|
||||
| Implies of t * t
|
||||
| AX of t (** AX phi <=> for all children of the current node phi holds *)
|
||||
| EX of t (** EX phi <=> exist a child of the current node such that phi holds *)
|
||||
| AF of t (** AF phi <=> for all path from the current node there is a descendant where phi holds *)
|
||||
| EF of t (** EF phi <=> there exits a a path from the current node with a descendant where phi hold *)
|
||||
| AG of t (** AG phi <=> for all discendant of the current node phi hold *)
|
||||
| EG of t (** EG phi <=>
|
||||
there exists a path (of descendants) from the current node where phi hold at each node of the path *)
|
||||
| AU of t * t (** AU(phi1, phi2) <=>
|
||||
for all paths from the current node phi1 holds in every node until ph2 holds *)
|
||||
| EU of t * t (** EU(phi1, phi2) <=>
|
||||
there exists a path from the current node such that phi1 holds until phi2 holds *)
|
||||
| EH of string list * t (** EH[classes]phi <=>
|
||||
there exists a node defining a super class in the hierarchy of the class
|
||||
defined by the current node (if any) where phi holds *)
|
||||
| ET of string list * transition_decl_to_stmt option * t (** ET[T][l] phi <=>
|
||||
there exists a descentant an of the current node such that an is of type in set T
|
||||
making a transition to a node an' via label l, such that in an phi holds. *)
|
||||
|
||||
(** the kind of AST nodes where formulas are evaluated *)
|
||||
type ast_node =
|
||||
| Stmt of Clang_ast_t.stmt
|
||||
| Decl of Clang_ast_t.decl
|
||||
|
||||
val eval_formula : t -> ast_node -> CLintersContext.context -> bool
|
@ -0,0 +1,175 @@
|
||||
(*
|
||||
* Copyright (c) 2016 - 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! Utils
|
||||
|
||||
open CFrontend_utils
|
||||
|
||||
|
||||
let get_ivar_attributes ivar_decl =
|
||||
let open Clang_ast_t in
|
||||
match ivar_decl with
|
||||
| ObjCIvarDecl (ivar_decl_info, _, _, _, _) ->
|
||||
(match Ast_utils.get_property_of_ivar ivar_decl_info.Clang_ast_t.di_pointer with
|
||||
| Some ObjCPropertyDecl (_, _, obj_c_property_decl_info) ->
|
||||
obj_c_property_decl_info.Clang_ast_t.opdi_property_attributes
|
||||
| _ -> [])
|
||||
| _ -> []
|
||||
|
||||
(* list of cxx references captured by stmt *)
|
||||
let captured_variables_cxx_ref stmt =
|
||||
let capture_var_is_cxx_ref reference_captured_vars captured_var =
|
||||
let decl_ref_opt = captured_var.Clang_ast_t.bcv_variable in
|
||||
match Ast_utils.get_decl_opt_with_decl_ref decl_ref_opt with
|
||||
| Some VarDecl (_, named_decl_info, qual_type, _)
|
||||
| Some ParmVarDecl (_, named_decl_info, qual_type, _)
|
||||
| Some ImplicitParamDecl (_, named_decl_info, qual_type, _) ->
|
||||
(match Ast_utils.get_desugared_type qual_type.Clang_ast_t.qt_type_ptr with
|
||||
| Some RValueReferenceType _ | Some LValueReferenceType _ ->
|
||||
named_decl_info::reference_captured_vars
|
||||
| _ -> reference_captured_vars)
|
||||
| _ -> reference_captured_vars in
|
||||
let captured_vars = match stmt with
|
||||
| Clang_ast_t.BlockExpr (_, _ , _, Clang_ast_t.BlockDecl (_, bdi)) ->
|
||||
bdi.Clang_ast_t.bdi_captured_variables
|
||||
| _ -> [] in
|
||||
IList.fold_left capture_var_is_cxx_ref [] captured_vars
|
||||
|
||||
let var_descs_name stmt =
|
||||
let capt_refs = captured_variables_cxx_ref stmt in
|
||||
let var_desc vars var_named_decl_info =
|
||||
vars ^ "'" ^ var_named_decl_info.Clang_ast_t.ni_name ^ "'" in
|
||||
IList.fold_left var_desc "" capt_refs
|
||||
|
||||
|
||||
type t = string * string list (* (name, [param1,...,paramK]) *)
|
||||
|
||||
let is_declaration_kind decl s =
|
||||
Clang_ast_proj.get_decl_kind_string decl = s
|
||||
|
||||
let is_statement_kind stmt s =
|
||||
Clang_ast_proj.get_stmt_kind_string stmt = s
|
||||
|
||||
(* st |= call_method(m) *)
|
||||
let call_method m st =
|
||||
match st with
|
||||
| Clang_ast_t.ObjCMessageExpr (_, _, _, omei) -> omei.omei_selector = m
|
||||
| _ -> false
|
||||
|
||||
let property_name_contains_word decl word =
|
||||
match Clang_ast_proj.get_named_decl_tuple decl with
|
||||
| Some (_, n) -> let pname = n.Clang_ast_t.ni_name in
|
||||
let rexp = Str.regexp_string_case_fold word in
|
||||
(try
|
||||
Str.search_forward rexp pname 0 >= 0
|
||||
with Not_found -> false)
|
||||
| _ -> false
|
||||
|
||||
let is_objc_extension = General_utils.is_objc_extension
|
||||
|
||||
let is_syntactically_global_var decl =
|
||||
Ast_utils.is_syntactically_global_var decl
|
||||
|
||||
let is_const_expr_var decl =
|
||||
Ast_utils.is_const_expr_var decl
|
||||
|
||||
let decl_ref_is_in names st =
|
||||
match st with
|
||||
| Clang_ast_t.DeclRefExpr (_, _, _, drti) ->
|
||||
(match drti.drti_decl_ref with
|
||||
| Some dr -> let ndi, _, _ = CFrontend_utils.Ast_utils.get_info_from_decl_ref dr in
|
||||
IList.exists (fun n -> n = ndi.ni_name) names
|
||||
| _ -> false)
|
||||
| _ -> false
|
||||
|
||||
let call_function_named st names =
|
||||
Ast_utils.exists_eventually_st decl_ref_is_in names st
|
||||
|
||||
let is_strong_property decl =
|
||||
match decl with
|
||||
| Clang_ast_t.ObjCPropertyDecl (_, _, pdi) ->
|
||||
ObjcProperty_decl.is_strong_property pdi
|
||||
| _ -> false
|
||||
|
||||
let is_assign_property decl =
|
||||
match decl with
|
||||
| Clang_ast_t.ObjCPropertyDecl (_, _, pdi) ->
|
||||
ObjcProperty_decl.is_assign_property pdi
|
||||
| _ -> false
|
||||
|
||||
let is_property_pointer_type decl =
|
||||
match decl with
|
||||
| Clang_ast_t.ObjCPropertyDecl (_, _, pdi) ->
|
||||
let type_ptr = pdi.opdi_type_ptr in
|
||||
let raw_ptr = Clang_ast_types.type_ptr_to_clang_pointer type_ptr in
|
||||
(match Clang_ast_main.PointerMap.find raw_ptr !CFrontend_config.pointer_type_index with
|
||||
| MemberPointerType _ | ObjCObjectPointerType _ | BlockPointerType _ -> true
|
||||
| TypedefType (_, tti) ->
|
||||
(Ast_utils.name_of_typedef_type_info tti) = CFrontend_config.id_cl
|
||||
| exception Not_found -> false
|
||||
| _ -> false)
|
||||
| _ -> false
|
||||
|
||||
let context_in_synchronized_block context =
|
||||
context.CLintersContext.in_synchronized_block
|
||||
|
||||
(* checks if ivar is defined among a set of fields and if it is atomic *)
|
||||
let is_ivar_atomic stmt =
|
||||
match stmt with
|
||||
| Clang_ast_t.ObjCIvarRefExpr (_, _, _, irei) ->
|
||||
let dr_ref = irei.Clang_ast_t.ovrei_decl_ref in
|
||||
let ivar_pointer = dr_ref.Clang_ast_t.dr_decl_pointer in
|
||||
(match Ast_utils.get_decl ivar_pointer with
|
||||
| Some d ->
|
||||
let attributes = get_ivar_attributes d in
|
||||
IList.exists (Ast_utils.property_attribute_eq `Atomic) attributes
|
||||
| _ -> false)
|
||||
| _ -> false
|
||||
|
||||
let is_method_property_accessor_of_ivar stmt context =
|
||||
let open Clang_ast_t in
|
||||
match stmt with
|
||||
| ObjCIvarRefExpr (_, _, _, irei) ->
|
||||
let dr_ref = irei.Clang_ast_t.ovrei_decl_ref in
|
||||
let ivar_pointer = dr_ref.Clang_ast_t.dr_decl_pointer in
|
||||
(match context.CLintersContext.current_method with
|
||||
| Some ObjCMethodDecl (_, _, mdi) ->
|
||||
if mdi.omdi_is_property_accessor then
|
||||
let property_opt = mdi.omdi_property_decl in
|
||||
match Ast_utils.get_decl_opt_with_decl_ref property_opt with
|
||||
| Some ObjCPropertyDecl (_, _, pdi) ->
|
||||
(match pdi.opdi_ivar_decl with
|
||||
| Some decl_ref -> decl_ref.dr_decl_pointer = ivar_pointer
|
||||
| None -> false)
|
||||
| _ -> false
|
||||
else false
|
||||
| _ -> false)
|
||||
| _ -> false
|
||||
|
||||
let is_objc_constructor context =
|
||||
match context.CLintersContext.current_method with
|
||||
| Some method_decl ->
|
||||
let method_name = (match Clang_ast_proj.get_named_decl_tuple method_decl with
|
||||
| Some (_, mnd) -> mnd.Clang_ast_t.ni_name
|
||||
| _ -> "") in
|
||||
Procname.is_objc_constructor method_name
|
||||
| _ -> false
|
||||
|
||||
|
||||
let is_objc_dealloc context =
|
||||
match context.CLintersContext.current_method with
|
||||
| Some method_decl ->
|
||||
let method_name = (match Clang_ast_proj.get_named_decl_tuple method_decl with
|
||||
| Some (_, mnd) -> mnd.Clang_ast_t.ni_name
|
||||
| _ -> "") in
|
||||
Procname.is_objc_dealloc method_name
|
||||
| _ -> false
|
||||
|
||||
let captures_cxx_references stmt =
|
||||
IList.length (captured_variables_cxx_ref stmt) > 0
|
@ -0,0 +1,46 @@
|
||||
(*
|
||||
* Copyright (c) 2016 - 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.
|
||||
*)
|
||||
|
||||
type t = string * string list (* (name, [param1,...,paramK]) *)
|
||||
|
||||
val var_descs_name : Clang_ast_t.stmt -> string (* Helper function *)
|
||||
|
||||
val call_method : string -> Clang_ast_t.stmt -> bool
|
||||
|
||||
val property_name_contains_word : Clang_ast_t.decl -> string -> bool
|
||||
|
||||
val is_objc_extension : bool
|
||||
|
||||
val is_syntactically_global_var : Clang_ast_t.decl -> bool
|
||||
|
||||
val is_const_expr_var : Clang_ast_t.decl -> bool
|
||||
|
||||
val is_declaration_kind : Clang_ast_t.decl -> string -> bool
|
||||
|
||||
val is_statement_kind : Clang_ast_t.stmt -> string -> bool
|
||||
|
||||
val call_function_named : Clang_ast_t.stmt -> string list -> bool
|
||||
|
||||
val is_strong_property : Clang_ast_t.decl -> bool
|
||||
|
||||
val is_assign_property : Clang_ast_t.decl -> bool
|
||||
|
||||
val is_property_pointer_type : Clang_ast_t.decl -> bool
|
||||
|
||||
val context_in_synchronized_block : CLintersContext.context -> bool
|
||||
|
||||
val is_ivar_atomic : Clang_ast_t.stmt -> bool
|
||||
|
||||
val is_method_property_accessor_of_ivar : Clang_ast_t.stmt -> CLintersContext.context -> bool
|
||||
|
||||
val is_objc_constructor : CLintersContext.context -> bool
|
||||
|
||||
val is_objc_dealloc : CLintersContext.context -> bool
|
||||
|
||||
val captures_cxx_references : Clang_ast_t.stmt -> bool
|
Loading…
Reference in new issue