2 * Copyright 2010, INRIA, University of Copenhagen
3 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
4 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
5 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
6 * This file is part of Coccinelle.
8 * Coccinelle is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, according to version 2 of the License.
12 * Coccinelle is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
27 module F
= Control_flow_c
29 (*****************************************************************************)
30 (* The functor argument *)
31 (*****************************************************************************)
33 (* info passed recursively in monad in addition to binding *)
35 optional_storage_iso
: bool;
36 optional_qualifier_iso
: bool;
37 value_format_iso
: bool;
38 optional_declarer_semicolon_iso
: bool;
39 current_rule_name
: string; (* used for errors *)
40 index
: int list
(* witness tree indices *)
43 module XTRANS
= struct
45 (* ------------------------------------------------------------------------*)
46 (* Combinators history *)
47 (* ------------------------------------------------------------------------*)
50 * type ('a, 'b) transformer =
51 * 'a -> 'b -> Lib_engine.metavars_binding -> 'b
55 * type ('a, 'b) transformer =
56 * 'a -> 'b -> Lib_engine.metavars_binding -> 'b option
57 * use an exception monad
60 * type tin = Lib_engine.metavars_binding
63 (* ------------------------------------------------------------------------*)
64 (* Standard type and operators *)
65 (* ------------------------------------------------------------------------*)
69 binding
: Lib_engine.metavars_binding
;
70 binding0
: Lib_engine.metavars_binding
; (* inherited variable *)
72 type 'x tout
= 'x
option
74 type ('a
, 'b
) matcher
= 'a
-> 'b
-> tin
-> ('a
* 'b
) tout
76 let (>>=) m f
= fun tin
->
79 | Some
(a
,b
) -> f a b tin
81 let return = fun x
-> fun tin
->
84 (* can have fail in transform now that the process is deterministic ? *)
88 let (>||>) m1 m2
= fun tin
->
91 | Some x
-> Some x
(* stop as soon as have found something *)
93 let (>|+|>) m1 m2
= m1
>||> m2
95 let (>&&>) f m
= fun tin
->
96 if f tin
then m tin
else fail tin
98 let optional_storage_flag f
= fun tin
->
99 f
(tin
.extra
.optional_storage_iso
) tin
101 let optional_qualifier_flag f
= fun tin
->
102 f
(tin
.extra
.optional_qualifier_iso
) tin
104 let value_format_flag f
= fun tin
->
105 f
(tin
.extra
.value_format_iso
) tin
107 let optional_declarer_semicolon_flag f
= fun tin
->
108 f
(tin
.extra
.optional_declarer_semicolon_iso
) tin
110 let mode = Cocci_vs_c.TransformMode
112 (* ------------------------------------------------------------------------*)
114 (* ------------------------------------------------------------------------*)
116 (* When env is used in + code, have to strip it more to avoid circular
117 references due to local variable information *)
123 | Ast_c.MetaExprVal
(e
,ml
) ->
124 (v
,Ast_c.MetaExprVal
(Lib_parsing_c.real_al_expr e
,ml
))
125 | Ast_c.MetaExprListVal
(es
) ->
126 (v
,Ast_c.MetaExprListVal
(Lib_parsing_c.real_al_arguments es
))
127 | Ast_c.MetaTypeVal
(ty
) ->
128 (v
,Ast_c.MetaTypeVal
(Lib_parsing_c.real_al_type ty
))
129 | Ast_c.MetaInitVal
(i
) ->
130 (v
,Ast_c.MetaInitVal
(Lib_parsing_c.real_al_init i
))
131 | Ast_c.MetaInitListVal
(is
) ->
132 (v
,Ast_c.MetaInitListVal
(Lib_parsing_c.real_al_inits is
))
133 | Ast_c.MetaDeclVal
(d
) ->
134 (v
,Ast_c.MetaDeclVal
(Lib_parsing_c.real_al_decl d
))
135 | Ast_c.MetaStmtVal
(s
) ->
136 (v
,Ast_c.MetaStmtVal
(Lib_parsing_c.real_al_statement s
))
141 (* ------------------------------------------------------------------------*)
143 (* ------------------------------------------------------------------------*)
144 let cocciExp = fun expf expa node
-> fun tin
->
147 Visitor_c.default_visitor_c_s
with
148 Visitor_c.kexpr_s
= (fun (k
, bigf) expb
->
149 match expf expa expb tin
with
150 | None
-> (* failed *) k expb
151 | Some
(x
, expb
) -> expb
);
154 Some
(expa
, Visitor_c.vk_node_s
bigf node
)
157 (* same as cocciExp, but for expressions in an expression, not expressions
159 let cocciExpExp = fun expf expa expb
-> fun tin
->
162 Visitor_c.default_visitor_c_s
with
163 Visitor_c.kexpr_s
= (fun (k
, bigf) expb
->
164 match expf expa expb tin
with
165 | None
-> (* failed *) k expb
166 | Some
(x
, expb
) -> expb
);
169 Some
(expa
, Visitor_c.vk_expr_s
bigf expb
)
172 let cocciTy = fun expf expa node
-> fun tin
->
175 Visitor_c.default_visitor_c_s
with
176 Visitor_c.ktype_s
= (fun (k
, bigf) expb
->
177 match expf expa expb tin
with
178 | None
-> (* failed *) k expb
179 | Some
(x
, expb
) -> expb
);
182 Some
(expa
, Visitor_c.vk_node_s
bigf node
)
184 let cocciInit = fun expf expa node
-> fun tin
->
187 Visitor_c.default_visitor_c_s
with
188 Visitor_c.kini_s
= (fun (k
, bigf) expb
->
189 match expf expa expb tin
with
190 | None
-> (* failed *) k expb
191 | Some
(x
, expb
) -> expb
);
194 Some
(expa
, Visitor_c.vk_node_s
bigf node
)
197 (* ------------------------------------------------------------------------*)
199 (* ------------------------------------------------------------------------*)
200 let check_pos info mck pos
=
202 | Ast_cocci.PLUS _
-> raise Impossible
203 | Ast_cocci.CONTEXT
(Ast_cocci.FixPos
(i1
,i2
),_
)
204 | Ast_cocci.MINUS
(Ast_cocci.FixPos
(i1
,i2
),_
,_
,_
) ->
205 pos
<= i2
&& pos
>= i1
206 | Ast_cocci.CONTEXT
(Ast_cocci.DontCarePos
,_
)
207 | Ast_cocci.MINUS
(Ast_cocci.DontCarePos
,_
,_
,_
) ->
214 "weird: dont have position info for the mcodekind in line %d column %d"
215 info
.Ast_cocci.line info
.Ast_cocci.column
)
217 failwith
"weird: dont have position info for the mcodekind"
220 let tag_with_mck mck ib
= fun tin
->
222 let cocciinforef = ib
.Ast_c.cocci_tag
in
223 let (oldmcode
, oldenvs
) = Ast_c.mcode_and_env_of_cocciref
cocciinforef in
227 if !Flag_parsing_cocci.sgrep_mode
228 then Sgrep.process_sgrep ib mck
233 (match mck, Ast_c.pinfo_of_info ib
with
234 | _
, Ast_c.AbstractLineTok _
-> raise Impossible
235 | Ast_cocci.MINUS
(_
), Ast_c.ExpandedTok _
->
238 "%s: %d: try to delete an expanded token: %s"
239 (Ast_c.file_of_info ib
)
240 (Ast_c.line_of_info ib
) (Ast_c.str_of_info ib
))
244 let many_context_count = function
245 Ast_cocci.BEFORE
(_
,Ast_cocci.MANY
) | Ast_cocci.AFTER
(_
,Ast_cocci.MANY
)
246 | Ast_cocci.BEFOREAFTER
(_
,_
,Ast_cocci.MANY
) -> true
249 let many_minus_count = function
250 Ast_cocci.REPLACEMENT
(_
,Ast_cocci.MANY
) -> true
253 (match (oldmcode
,mck) with
254 | (Ast_cocci.CONTEXT
(_
,Ast_cocci.NOTHING
), _
) ->
255 (* nothing there, so take the new stuff *)
256 let update_inst inst
= function
257 Ast_cocci.MINUS
(pos
,_
,adj
,any_xxs
) ->
258 Ast_cocci.MINUS
(pos
,inst
,adj
,any_xxs
)
260 (* clean_env actually only needed if there is an addition
261 not sure the extra efficiency would be worth duplicating the code *)
263 Some
(update_inst tin
.extra
.index
mck, [clean_env tin
.binding
])
264 | (_
, Ast_cocci.CONTEXT
(_
,Ast_cocci.NOTHING
)) ->
265 (* can this case occur? stay with the old stuff *)
267 | (Ast_cocci.MINUS
(old_pos
,old_inst
,old_adj
,Ast_cocci.NOREPLACEMENT
),
268 Ast_cocci.MINUS
(new_pos
,new_inst
,new_adj
,Ast_cocci.NOREPLACEMENT
))
269 when old_pos
= new_pos
270 (* not sure why the following condition is useful.
271 should be ok to double remove even if the environments are
274 (List.mem tin.binding oldenvs or !Flag.sgrep_mode2) *)
275 (* no way to combine adjacency information, just drop one *)
279 (old_pos
,Common.union_set old_inst new_inst
,old_adj
,
280 Ast_cocci.NOREPLACEMENT
),
282 (if !Flag_matcher.show_misc
283 then pr2_once
"already tagged but only removed, so safe")
286 | (Ast_cocci.MINUS
(old_pos
,old_inst
,old_adj
,old_modif
),
287 Ast_cocci.MINUS
(new_pos
,new_inst
,new_adj
,new_modif
))
288 when old_pos
= new_pos
&&
289 old_modif
= new_modif
&& many_minus_count old_modif
->
292 Some
(Ast_cocci.MINUS
(old_pos
,Common.union_set old_inst new_inst
,
294 (clean_env tin
.binding
)::oldenvs
)
296 | (Ast_cocci.CONTEXT
(old_pos
,old_modif
),
297 Ast_cocci.CONTEXT
(new_pos
,new_modif
))
298 when old_pos
= new_pos
&&
299 old_modif
= new_modif
&& many_context_count old_modif
->
300 (* iteration only allowed on context; no way to replace something
301 more than once; now no need for iterable; just check a flag *)
304 Some
(Ast_cocci.CONTEXT
(old_pos
,old_modif
),
305 (clean_env tin
.binding
)::oldenvs
)
315 pad: if dont want cocci write:
317 (match Ast_c.pinfo_of_info ib with
318 Ast_c.FakeTok _ -> "already tagged fake token"
320 let pm str mcode env
=
322 "%s modification:\n%s\nAccording to environment %d:\n%s\n"
324 (Common.format_to_string
326 Pretty_print_cocci.print_mcodekind mcode
))
330 (function ((r
,vr
),vl
) ->
331 Printf.sprintf
" %s.%s -> %s" r vr
332 (Common.format_to_string
334 Pretty_print_engine.pp_binding_kind vl
)))
336 flush stdout
; flush stderr
;
338 ("\n"^
(String.concat
"\n"
339 (List.map
(pm "previous" oldmcode
) oldenvs
)) ^
"\n"
340 ^
(pm "current" mck tin
.binding
));
342 (match Ast_c.pinfo_of_info ib
with
344 Common.sprintf
"%s: already tagged fake token\n"
345 tin
.extra
.current_rule_name
348 "%s: already tagged token:\nC code context\n%s"
349 tin
.extra
.current_rule_name
350 (Common.error_message
(Ast_c.file_of_info ib
)
351 (Ast_c.str_of_info ib
, Ast_c.opos_of_info ib
)))
355 let tokenf ia ib
= fun tin
->
356 let (_
,i
,mck,_
) = ia
in
357 let pos = Ast_c.info_to_fixpos ib
in
358 if check_pos (Some i
) mck pos
359 then return (ia
, tag_with_mck mck ib tin
) tin
362 let tokenf_mck mck ib
= fun tin
->
363 let pos = Ast_c.info_to_fixpos ib
in
364 if check_pos None
mck pos
365 then return (mck, tag_with_mck mck ib tin
) tin
369 (* ------------------------------------------------------------------------*)
370 (* Distribute mcode *)
371 (* ------------------------------------------------------------------------*)
373 (* When in the SP we attach something to a metavariable, or delete it, as in
376 * we have to minusize all the token that compose S in the C code, and
377 * attach the 'foo();' to the right token, the one at the very right.
380 type 'a distributer
=
381 (Ast_c.info
-> Ast_c.info
) * (* what to do on left *)
382 (Ast_c.info
-> Ast_c.info
) * (* what to do on middle *)
383 (Ast_c.info
-> Ast_c.info
) * (* what to do on right *)
384 (Ast_c.info
-> Ast_c.info
) -> (* what to do on both *)
387 let distribute_mck mcodekind distributef expr tin
=
389 | Ast_cocci.MINUS
(pos,_
,adj
,any_xxs
) ->
390 let inst = tin
.extra
.index
in
393 tag_with_mck (Ast_cocci.MINUS
(pos,inst,adj
,any_xxs
)) ib tin
),
396 (Ast_cocci.MINUS
(pos,inst,adj
,Ast_cocci.NOREPLACEMENT
)) ib tin
),
399 (Ast_cocci.MINUS
(pos,inst,adj
,Ast_cocci.NOREPLACEMENT
)) ib tin
),
401 tag_with_mck (Ast_cocci.MINUS
(pos,inst,adj
,any_xxs
)) ib tin
)
403 | Ast_cocci.CONTEXT
(pos,any_befaft
) ->
404 (match any_befaft
with
405 | Ast_cocci.NOTHING
-> expr
407 | Ast_cocci.BEFORE
(xxs
,c
) ->
409 (fun ib
-> tag_with_mck
410 (Ast_cocci.CONTEXT
(pos,Ast_cocci.BEFORE
(xxs
,c
))) ib tin
),
413 (fun ib
-> tag_with_mck
414 (Ast_cocci.CONTEXT
(pos,Ast_cocci.BEFORE
(xxs
,c
))) ib tin
)
416 | Ast_cocci.AFTER
(xxs
,c
) ->
420 (fun ib
-> tag_with_mck
421 (Ast_cocci.CONTEXT
(pos,Ast_cocci.AFTER
(xxs
,c
))) ib tin
),
422 (fun ib
-> tag_with_mck
423 (Ast_cocci.CONTEXT
(pos,Ast_cocci.AFTER
(xxs
,c
))) ib tin
)
426 | Ast_cocci.BEFOREAFTER
(xxs
, yys
, c
) ->
428 (fun ib
-> tag_with_mck
429 (Ast_cocci.CONTEXT
(pos,Ast_cocci.BEFORE
(xxs
,c
))) ib tin
),
431 (fun ib
-> tag_with_mck
432 (Ast_cocci.CONTEXT
(pos,Ast_cocci.AFTER
(yys
,c
))) ib tin
),
433 (fun ib
-> tag_with_mck
434 (Ast_cocci.CONTEXT
(pos,Ast_cocci.BEFOREAFTER
(xxs
,yys
,c
)))
439 | Ast_cocci.PLUS _
-> raise Impossible
442 (* use new strategy, collect ii, sort, recollect and tag *)
444 let mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
) =
446 Visitor_c.default_visitor_c_s
with
447 Visitor_c.kinfo_s
= (fun (k
,bigf) i
->
448 let pos = Ast_c.info_to_fixpos i
in
450 | _
when Ast_cocci.equal_pos
pos maxpos
&&
451 Ast_cocci.equal_pos
pos minpos
-> bop i
452 | _
when Ast_cocci.equal_pos
pos maxpos
-> rop i
453 | _
when Ast_cocci.equal_pos
pos minpos
-> lop i
459 let distribute_mck_expr (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) -> fun x
->
460 Visitor_c.vk_expr_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
)) x
462 let distribute_mck_args (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) -> fun x
->
463 Visitor_c.vk_args_splitted_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
)) x
465 let distribute_mck_type (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) -> fun x
->
466 Visitor_c.vk_type_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
)) x
468 let distribute_mck_decl (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) -> fun x
->
469 Visitor_c.vk_decl_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
)) x
471 let distribute_mck_field (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) -> fun x
->
472 Visitor_c.vk_struct_field_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
)) x
474 let distribute_mck_ini (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) -> fun x
->
475 Visitor_c.vk_ini_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
)) x
477 let distribute_mck_inis (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) -> fun x
->
478 Visitor_c.vk_inis_splitted_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
)) x
480 let distribute_mck_param (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) -> fun x
->
481 Visitor_c.vk_param_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
)) x
483 let distribute_mck_params (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) ->fun x
->
484 Visitor_c.vk_params_splitted_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
))
487 let distribute_mck_node (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) ->fun x
->
488 Visitor_c.vk_node_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
))
491 let distribute_mck_enum_fields (maxpos
, minpos
) =
492 fun (lop
,mop
,rop
,bop
) ->fun x
->
493 Visitor_c.vk_enum_fields_splitted_s
494 (mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
))
497 let distribute_mck_struct_fields (maxpos
, minpos
) =
498 fun (lop
,mop
,rop
,bop
) ->fun x
->
499 Visitor_c.vk_struct_fields_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
))
502 let distribute_mck_cst (maxpos
, minpos
) =
503 fun (lop
,mop
,rop
,bop
) ->fun x
->
504 Visitor_c.vk_cst_s
(mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
))
508 let distribute_mck_define_params (maxpos
, minpos
) = fun (lop
,mop
,rop
,bop
) ->
510 Visitor_c.vk_define_params_splitted_s
511 (mk_bigf (maxpos
, minpos
) (lop
,mop
,rop
,bop
))
516 | Ast_cocci.PLUS _
-> raise Impossible
517 | Ast_cocci.CONTEXT
(Ast_cocci.FixPos
(i1
,i2
),_
)
518 | Ast_cocci.MINUS
(Ast_cocci.FixPos
(i1
,i2
),_
,_
,_
) ->
519 Ast_cocci.FixPos
(i1
,i2
)
520 | Ast_cocci.CONTEXT
(Ast_cocci.DontCarePos
,_
)
521 | Ast_cocci.MINUS
(Ast_cocci.DontCarePos
,_
,_
,_
) ->
522 Ast_cocci.DontCarePos
523 | _
-> failwith
"weird: dont have position info for the mcodekind 2"
525 let distrf (ii_of_x_f
, distribute_mck_x_f
) =
526 fun ia x
-> fun tin
->
527 let mck = Ast_cocci.get_mcodekind ia
in
528 let (max
, min
) = Lib_parsing_c.max_min_by_pos
(ii_of_x_f x
)
531 (* bug: check_pos mck max && check_pos mck min
533 * if do that then if have - f(...); and in C f(1,2); then we
534 * would get a "already tagged" because the '...' would sucess in
535 * transformaing both '1' and '1,2'. So being in the range is not
536 * enough. We must be equal exactly to the range!
538 (match get_pos mck with
539 | Ast_cocci.DontCarePos
-> true
540 | Ast_cocci.FixPos
(i1
, i2
) ->
541 i1
=*= min
&& i2
=*= max
542 | _
-> raise Impossible
548 distribute_mck mck (distribute_mck_x_f
(max
,min
)) x tin
553 let distrf_e = distrf (Lib_parsing_c.ii_of_expr
, distribute_mck_expr)
554 let distrf_args = distrf (Lib_parsing_c.ii_of_args
, distribute_mck_args)
555 let distrf_type = distrf (Lib_parsing_c.ii_of_type
, distribute_mck_type)
556 let distrf_param = distrf (Lib_parsing_c.ii_of_param
, distribute_mck_param)
557 let distrf_params = distrf (Lib_parsing_c.ii_of_params
,distribute_mck_params)
558 let distrf_ini = distrf (Lib_parsing_c.ii_of_ini
,distribute_mck_ini)
559 let distrf_inis = distrf (Lib_parsing_c.ii_of_inis
,distribute_mck_inis)
560 let distrf_decl = distrf (Lib_parsing_c.ii_of_decl
,distribute_mck_decl)
561 let distrf_field = distrf (Lib_parsing_c.ii_of_field
,distribute_mck_field)
562 let distrf_node = distrf (Lib_parsing_c.ii_of_node
,distribute_mck_node)
563 let distrf_enum_fields =
564 distrf (Lib_parsing_c.ii_of_enum_fields
, distribute_mck_enum_fields)
565 let distrf_struct_fields =
566 distrf (Lib_parsing_c.ii_of_struct_fields
, distribute_mck_struct_fields)
568 distrf (Lib_parsing_c.ii_of_cst
, distribute_mck_cst)
569 let distrf_define_params =
570 distrf (Lib_parsing_c.ii_of_define_params
,distribute_mck_define_params)
573 (* ------------------------------------------------------------------------*)
575 (* ------------------------------------------------------------------------*)
576 let meta_name_to_str (s1
, s2
) = s1 ^
"." ^ s2
578 let envf keep inherited
= fun (s
, value, _
) f tin
->
579 let s = Ast_cocci.unwrap_mcode
s in
581 if keep
=*= Type_cocci.Saved
583 try Some
(List.assoc
s tin
.binding
)
586 "Don't find value for metavariable %s in the environment"
587 (meta_name_to_str s));
590 (* not raise Impossible! *)
597 (* Ex: in cocci_vs_c someone wants to add a binding. Here in
598 * transformation3 the value for this var may be already in the
599 * env, because for instance its value were fixed in a previous
600 * SmPL rule. So here we want to check that this is the same value.
601 * If forget to do the check, what can happen ? Because of Exp
602 * and other disjunctive feature of cocci_vs_c (>||>), we
603 * may accept a match at a wrong position. Maybe later this
604 * will be detected via the pos system on tokens, but maybe
605 * not. So safer to keep the check.
611 then Cocci_vs_c.equal_inh_metavarval
612 else Cocci_vs_c.equal_metavarval
in
613 if equal value value'
618 let check_idconstraint matcher c id
= fun f tin
-> f
() tin
619 let check_constraints_ne matcher constraints exp
= fun f tin
-> f
() tin
621 (* ------------------------------------------------------------------------*)
622 (* Environment, allbounds *)
623 (* ------------------------------------------------------------------------*)
624 let (all_bound
: Ast_cocci.meta_name list
-> tin
-> bool) = fun l tin
->
625 true (* in transform we don't care ? *)
629 (*****************************************************************************)
631 (*****************************************************************************)
632 module TRANS
= Cocci_vs_c.COCCI_VS_C
(XTRANS
)
635 let transform_re_node a b tin
=
636 match TRANS.rule_elem_node a b tin
with
637 | None
-> raise Impossible
638 | Some
(_sp
, b'
) -> b'
640 let (transform2
: string (* rule name *) -> string list
(* dropped_isos *) ->
641 Lib_engine.metavars_binding
(* inherited bindings *) ->
642 Lib_engine.numbered_transformation_info
-> F.cflow
-> F.cflow
) =
643 fun rule_name dropped_isos binding0 xs cflow
->
645 optional_storage_iso
= not
(List.mem
"optional_storage" dropped_isos
);
646 optional_qualifier_iso
= not
(List.mem
"optional_qualifier" dropped_isos
);
647 value_format_iso
= not
(List.mem
"value_format" dropped_isos
);
648 optional_declarer_semicolon_iso
=
649 not
(List.mem
"optional_declarer_semicolon" dropped_isos
);
650 current_rule_name
= rule_name
;
654 (* find the node, transform, update the node, and iter for all elements *)
656 xs
+> List.fold_left
(fun acc
(index
, (nodei
, binding
, rule_elem
)) ->
657 (* subtil: not cflow#nodes but acc#nodes *)
658 let node = acc#nodes#assoc nodei
in
660 if !Flag.show_transinfo
661 then pr2
(Printf.sprintf
"transform one node: %d" nodei
);
664 XTRANS.extra = {extra with index
= index
};
665 XTRANS.binding
= binding0
@binding
;
666 XTRANS.binding0
= []; (* not used - everything constant for trans *)
669 let node'
= transform_re_node rule_elem
node tin in
671 (* assert that have done something. But with metaruleElem sometimes
672 dont modify fake nodes. So special case before on Fake nodes. *)
673 (match F.unwrap
node with
674 | F.Enter
| F.Exit
| F.ErrorExit
675 | F.EndStatement _
| F.CaseNode _
677 | F.TrueNode
| F.FalseNode
| F.AfterNode
| F.FallThroughNode
679 | _
-> () (* assert (not (node =*= node')); *)
682 (* useless, we dont go back from flow to ast now *)
683 (* let node' = lastfix_comma_struct node' in *)
685 acc#replace_node
(nodei
, node'
);
691 let transform a b c d e
=
692 Common.profile_code
"Transformation3.transform"
693 (fun () -> transform2 a b c d e
)