Coccinelle release 0.2.5-rc8
[bpt/coccinelle.git] / engine / transformation_c.ml
CommitLineData
9bc82bae
C
1(*
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.
7 *
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.
11 *
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.
16 *
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/>.
19 *
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
22 *)
23
24
34e49164
C
25open Common
26
27module F = Control_flow_c
28
29(*****************************************************************************)
ae4735db 30(* The functor argument *)
34e49164
C
31(*****************************************************************************)
32
33(* info passed recursively in monad in addition to binding *)
ae4735db 34type xinfo = {
34e49164
C
35 optional_storage_iso : bool;
36 optional_qualifier_iso : bool;
37 value_format_iso : bool;
38 current_rule_name : string; (* used for errors *)
708f4980 39 index : int list (* witness tree indices *)
34e49164
C
40}
41
42module XTRANS = struct
43
44 (* ------------------------------------------------------------------------*)
ae4735db 45 (* Combinators history *)
34e49164
C
46 (* ------------------------------------------------------------------------*)
47 (*
ae4735db
C
48 * version0:
49 * type ('a, 'b) transformer =
34e49164 50 * 'a -> 'b -> Lib_engine.metavars_binding -> 'b
ae4735db
C
51 * exception NoMatch
52 *
34e49164 53 * version1:
ae4735db 54 * type ('a, 'b) transformer =
34e49164 55 * 'a -> 'b -> Lib_engine.metavars_binding -> 'b option
ae4735db
C
56 * use an exception monad
57 *
34e49164
C
58 * version2:
59 * type tin = Lib_engine.metavars_binding
60 *)
61
62 (* ------------------------------------------------------------------------*)
ae4735db 63 (* Standard type and operators *)
34e49164
C
64 (* ------------------------------------------------------------------------*)
65
ae4735db 66 type tin = {
34e49164
C
67 extra: xinfo;
68 binding: Lib_engine.metavars_binding;
1be43e12 69 binding0: Lib_engine.metavars_binding; (* inherited variable *)
34e49164
C
70 }
71 type 'x tout = 'x option
72
73 type ('a, 'b) matcher = 'a -> 'b -> tin -> ('a * 'b) tout
74
ae4735db 75 let (>>=) m f = fun tin ->
34e49164
C
76 match m tin with
77 | None -> None
78 | Some (a,b) -> f a b tin
79
ae4735db 80 let return = fun x -> fun tin ->
34e49164
C
81 Some x
82
83 (* can have fail in transform now that the process is deterministic ? *)
ae4735db 84 let fail = fun tin ->
34e49164
C
85 None
86
ae4735db 87 let (>||>) m1 m2 = fun tin ->
34e49164
C
88 match m1 tin with
89 | None -> m2 tin
90 | Some x -> Some x (* stop as soon as have found something *)
91
92 let (>|+|>) m1 m2 = m1 >||> m2
93
ae4735db 94 let (>&&>) f m = fun tin ->
34e49164
C
95 if f tin then m tin else fail tin
96
ae4735db 97 let optional_storage_flag f = fun tin ->
34e49164
C
98 f (tin.extra.optional_storage_iso) tin
99
ae4735db 100 let optional_qualifier_flag f = fun tin ->
34e49164
C
101 f (tin.extra.optional_qualifier_iso) tin
102
ae4735db 103 let value_format_flag f = fun tin ->
34e49164
C
104 f (tin.extra.value_format_iso) tin
105
485bce71 106 let mode = Cocci_vs_c.TransformMode
34e49164
C
107
108 (* ------------------------------------------------------------------------*)
ae4735db 109 (* Exp *)
34e49164 110 (* ------------------------------------------------------------------------*)
ae4735db 111 let cocciExp = fun expf expa node -> fun tin ->
34e49164 112
ae4735db
C
113 let bigf = {
114 Visitor_c.default_visitor_c_s with
34e49164
C
115 Visitor_c.kexpr_s = (fun (k, bigf) expb ->
116 match expf expa expb tin with
117 | None -> (* failed *) k expb
118 | Some (x, expb) -> expb);
119 }
120 in
121 Some (expa, Visitor_c.vk_node_s bigf node)
122
123
124 (* same as cocciExp, but for expressions in an expression, not expressions
125 in a node *)
ae4735db 126 let cocciExpExp = fun expf expa expb -> fun tin ->
34e49164 127
ae4735db
C
128 let bigf = {
129 Visitor_c.default_visitor_c_s with
34e49164
C
130 Visitor_c.kexpr_s = (fun (k, bigf) expb ->
131 match expf expa expb tin with
132 | None -> (* failed *) k expb
133 | Some (x, expb) -> expb);
134 }
135 in
136 Some (expa, Visitor_c.vk_expr_s bigf expb)
137
138
ae4735db 139 let cocciTy = fun expf expa node -> fun tin ->
34e49164 140
ae4735db
C
141 let bigf = {
142 Visitor_c.default_visitor_c_s with
34e49164
C
143 Visitor_c.ktype_s = (fun (k, bigf) expb ->
144 match expf expa expb tin with
145 | None -> (* failed *) k expb
146 | Some (x, expb) -> expb);
147 }
148 in
149 Some (expa, Visitor_c.vk_node_s bigf node)
150
ae4735db 151 let cocciInit = fun expf expa node -> fun tin ->
1be43e12 152
ae4735db
C
153 let bigf = {
154 Visitor_c.default_visitor_c_s with
1be43e12
C
155 Visitor_c.kini_s = (fun (k, bigf) expb ->
156 match expf expa expb tin with
157 | None -> (* failed *) k expb
158 | Some (x, expb) -> expb);
159 }
160 in
161 Some (expa, Visitor_c.vk_node_s bigf node)
162
34e49164
C
163
164 (* ------------------------------------------------------------------------*)
ae4735db 165 (* Tokens *)
34e49164 166 (* ------------------------------------------------------------------------*)
ae4735db 167 let check_pos info mck pos =
34e49164 168 match mck with
951c7801 169 | Ast_cocci.PLUS _ -> raise Impossible
708f4980 170 | Ast_cocci.CONTEXT (Ast_cocci.FixPos (i1,i2),_)
ae4735db 171 | Ast_cocci.MINUS (Ast_cocci.FixPos (i1,i2),_,_,_) ->
34e49164 172 pos <= i2 && pos >= i1
708f4980 173 | Ast_cocci.CONTEXT (Ast_cocci.DontCarePos,_)
ae4735db 174 | Ast_cocci.MINUS (Ast_cocci.DontCarePos,_,_,_) ->
34e49164
C
175 true
176 | _ ->
177 match info with
178 Some info ->
179 failwith
180 (Printf.sprintf
0708f913 181 "weird: dont have position info for the mcodekind in line %d column %d"
34e49164
C
182 info.Ast_cocci.line info.Ast_cocci.column)
183 | None ->
0708f913 184 failwith "weird: dont have position info for the mcodekind"
34e49164
C
185
186
ae4735db 187 let tag_with_mck mck ib = fun tin ->
34e49164
C
188
189 let cocciinforef = ib.Ast_c.cocci_tag in
951c7801 190 let (oldmcode, oldenvs) = Ast_c.mcode_and_env_of_cocciref cocciinforef in
34e49164
C
191
192 let mck =
ae4735db 193 (* coccionly:
34e49164
C
194 if !Flag_parsing_cocci.sgrep_mode
195 then Sgrep.process_sgrep ib mck
ae4735db 196 else
485bce71 197 *)
ae4735db 198 mck
34e49164
C
199 in
200 (match mck, Ast_c.pinfo_of_info ib with
201 | _, Ast_c.AbstractLineTok _ -> raise Impossible
ae4735db 202 | Ast_cocci.MINUS(_), Ast_c.ExpandedTok _ ->
34e49164
C
203 failwith ("try to delete an expanded token: " ^ (Ast_c.str_of_info ib))
204 | _ -> ()
205 );
206
951c7801
C
207 let many_count = function
208 Ast_cocci.BEFORE(_,Ast_cocci.MANY) | Ast_cocci.AFTER(_,Ast_cocci.MANY)
209 | Ast_cocci.BEFOREAFTER(_,_,Ast_cocci.MANY) -> true
210 | _ -> false in
211
212 (match (oldmcode,mck) with
213 | (Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING), _) ->
214 (* nothing there, so take the new stuff *)
708f4980
C
215 let update_inst inst = function
216 Ast_cocci.MINUS (pos,_,adj,any_xxs) ->
217 Ast_cocci.MINUS (pos,inst,adj,any_xxs)
218 | mck -> mck in
951c7801
C
219 cocciinforef := Some (update_inst tin.extra.index mck, [tin.binding])
220 | (_, Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING)) ->
221 (* can this case occur? stay with the old stuff *)
222 ()
708f4980
C
223 | (Ast_cocci.MINUS(old_pos,old_inst,old_adj,[]),
224 Ast_cocci.MINUS(new_pos,new_inst,new_adj,[]))
951c7801
C
225 when old_pos = new_pos &&
226 (List.mem tin.binding oldenvs or !Flag.sgrep_mode2)
708f4980
C
227 (* no way to combine adjacency information, just drop one *)
228 ->
229 cocciinforef := Some
230 (Ast_cocci.MINUS
231 (old_pos,Common.union_set old_inst new_inst,old_adj,[]),
951c7801 232 [tin.binding]);
708f4980 233 (if !Flag_matcher.show_misc
951c7801
C
234 then pr2 "already tagged but only removed, so safe")
235
236 | (Ast_cocci.CONTEXT(old_pos,old_modif),
237 Ast_cocci.CONTEXT(new_pos,new_modif))
238 when old_pos = new_pos &&
239 old_modif = new_modif && many_count old_modif ->
240 (* iteration only allowed on context; no way to replace something
241 more than once; now no need for iterable; just check a flag *)
242
243 cocciinforef :=
244 Some(Ast_cocci.CONTEXT(old_pos,old_modif),tin.binding::oldenvs)
708f4980 245
ae4735db
C
246 | _ ->
247 (* coccionly:
34e49164
C
248 if !Flag.sgrep_mode2
249 then ib (* safe *)
ae4735db 250 else
485bce71
C
251 *)
252 begin
ae4735db 253 (* coccionly:
708f4980
C
254 pad: if dont want cocci write:
255 failwith
b1b2de81
C
256 (match Ast_c.pinfo_of_info ib with
257 Ast_c.FakeTok _ -> "already tagged fake token"
708f4980
C
258 *)
259 let pm str mcode env =
260 Printf.sprintf
951c7801 261 "%s modification:\n%s\nAccording to environment %d:\n%s\n"
708f4980
C
262 str
263 (Common.format_to_string
264 (function _ ->
265 Pretty_print_cocci.print_mcodekind mcode))
951c7801 266 (List.length env)
708f4980
C
267 (String.concat "\n"
268 (List.map
269 (function ((r,vr),vl) ->
270 Printf.sprintf " %s.%s -> %s" r vr
271 (Common.format_to_string
272 (function _ ->
273 Pretty_print_engine.pp_binding_kind vl)))
274 env)) in
275 flush stdout; flush stderr;
276 Common.pr2
951c7801
C
277 ("\n"^ (String.concat "\n"
278 (List.map (pm "previous" oldmcode) oldenvs)) ^ "\n"
279 ^ (pm "current" mck tin.binding));
708f4980
C
280 failwith
281 (match Ast_c.pinfo_of_info ib with
282 Ast_c.FakeTok _ ->
283 Common.sprintf "%s: already tagged fake token\n"
284 tin.extra.current_rule_name
b1b2de81 285 | _ ->
708f4980
C
286 Printf.sprintf
287 "%s: already tagged token:\nC code context\n%s"
b1b2de81
C
288 tin.extra.current_rule_name
289 (Common.error_message (Ast_c.file_of_info ib)
290 (Ast_c.str_of_info ib, Ast_c.opos_of_info ib)))
951c7801
C
291 end);
292 ib
34e49164 293
ae4735db 294 let tokenf ia ib = fun tin ->
34e49164
C
295 let (_,i,mck,_) = ia in
296 let pos = Ast_c.info_to_fixpos ib in
ae4735db 297 if check_pos (Some i) mck pos
34e49164
C
298 then return (ia, tag_with_mck mck ib tin) tin
299 else fail tin
300
ae4735db 301 let tokenf_mck mck ib = fun tin ->
34e49164 302 let pos = Ast_c.info_to_fixpos ib in
ae4735db 303 if check_pos None mck pos
34e49164
C
304 then return (mck, tag_with_mck mck ib tin) tin
305 else fail tin
306
307
308 (* ------------------------------------------------------------------------*)
ae4735db 309 (* Distribute mcode *)
34e49164
C
310 (* ------------------------------------------------------------------------*)
311
312 (* When in the SP we attach something to a metavariable, or delete it, as in
313 * - S
314 * + foo();
ae4735db
C
315 * we have to minusize all the token that compose S in the C code, and
316 * attach the 'foo();' to the right token, the one at the very right.
34e49164
C
317 *)
318
ae4735db 319 type 'a distributer =
34e49164
C
320 (Ast_c.info -> Ast_c.info) * (* what to do on left *)
321 (Ast_c.info -> Ast_c.info) * (* what to do on middle *)
322 (Ast_c.info -> Ast_c.info) * (* what to do on right *)
323 (Ast_c.info -> Ast_c.info) -> (* what to do on both *)
324 'a -> 'a
325
326 let distribute_mck mcodekind distributef expr tin =
327 match mcodekind with
ae4735db 328 | Ast_cocci.MINUS (pos,_,adj,any_xxs) ->
708f4980 329 let inst = tin.extra.index in
34e49164 330 distributef (
708f4980
C
331 (fun ib ->
332 tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,any_xxs)) ib tin),
333 (fun ib ->
334 tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,[])) ib tin),
335 (fun ib ->
336 tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,[])) ib tin),
337 (fun ib ->
338 tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,any_xxs)) ib tin)
34e49164 339 ) expr
ae4735db 340 | Ast_cocci.CONTEXT (pos,any_befaft) ->
34e49164
C
341 (match any_befaft with
342 | Ast_cocci.NOTHING -> expr
ae4735db
C
343
344 | Ast_cocci.BEFORE (xxs,c) ->
34e49164 345 distributef (
ae4735db 346 (fun ib -> tag_with_mck
951c7801 347 (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE (xxs,c))) ib tin),
ae4735db
C
348 (fun x -> x),
349 (fun x -> x),
350 (fun ib -> tag_with_mck
951c7801 351 (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE (xxs,c))) ib tin)
34e49164 352 ) expr
ae4735db 353 | Ast_cocci.AFTER (xxs,c) ->
34e49164 354 distributef (
ae4735db
C
355 (fun x -> x),
356 (fun x -> x),
357 (fun ib -> tag_with_mck
951c7801 358 (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER (xxs,c))) ib tin),
ae4735db 359 (fun ib -> tag_with_mck
951c7801 360 (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER (xxs,c))) ib tin)
34e49164
C
361 ) expr
362
ae4735db 363 | Ast_cocci.BEFOREAFTER (xxs, yys, c) ->
34e49164 364 distributef (
ae4735db 365 (fun ib -> tag_with_mck
951c7801 366 (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE (xxs,c))) ib tin),
ae4735db
C
367 (fun x -> x),
368 (fun ib -> tag_with_mck
951c7801 369 (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER (yys,c))) ib tin),
ae4735db 370 (fun ib -> tag_with_mck
951c7801 371 (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFOREAFTER (xxs,yys,c)))
34e49164
C
372 ib tin)
373 ) expr
374
375 )
951c7801 376 | Ast_cocci.PLUS _ -> raise Impossible
34e49164
C
377
378
379 (* use new strategy, collect ii, sort, recollect and tag *)
380
ae4735db
C
381 let mk_bigf (maxpos, minpos) (lop,mop,rop,bop) =
382 let bigf = {
34e49164 383 Visitor_c.default_visitor_c_s with
ae4735db 384 Visitor_c.kinfo_s = (fun (k,bigf) i ->
34e49164
C
385 let pos = Ast_c.info_to_fixpos i in
386 match () with
387 | _ when Ast_cocci.equal_pos pos maxpos &&
388 Ast_cocci.equal_pos pos minpos -> bop i
389 | _ when Ast_cocci.equal_pos pos maxpos -> rop i
390 | _ when Ast_cocci.equal_pos pos minpos -> lop i
391 | _ -> mop i
392 )
393 } in
394 bigf
395
396 let distribute_mck_expr (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
397 Visitor_c.vk_expr_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
398
399 let distribute_mck_args (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
400 Visitor_c.vk_args_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
401
402 let distribute_mck_type (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
403 Visitor_c.vk_type_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
404
413ffc02
C
405 let distribute_mck_decl (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
406 Visitor_c.vk_decl_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
407
408 let distribute_mck_field (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
409 Visitor_c.vk_struct_field_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
410
34e49164
C
411 let distribute_mck_ini (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
412 Visitor_c.vk_ini_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
413
c491d8ee
C
414 let distribute_mck_inis (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
415 Visitor_c.vk_inis_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
416
34e49164
C
417 let distribute_mck_param (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
418 Visitor_c.vk_param_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
419
420 let distribute_mck_params (maxpos, minpos) = fun (lop,mop,rop,bop) ->fun x ->
421 Visitor_c.vk_params_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
422 x
423
424 let distribute_mck_node (maxpos, minpos) = fun (lop,mop,rop,bop) ->fun x ->
425 Visitor_c.vk_node_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
426 x
427
c491d8ee
C
428 let distribute_mck_enum_fields (maxpos, minpos) =
429 fun (lop,mop,rop,bop) ->fun x ->
430 Visitor_c.vk_enum_fields_splitted_s
431 (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
432 x
433
ae4735db 434 let distribute_mck_struct_fields (maxpos, minpos) =
34e49164
C
435 fun (lop,mop,rop,bop) ->fun x ->
436 Visitor_c.vk_struct_fields_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
437 x
438
ae4735db 439 let distribute_mck_cst (maxpos, minpos) =
34e49164
C
440 fun (lop,mop,rop,bop) ->fun x ->
441 Visitor_c.vk_cst_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
442 x
443
444
ae4735db 445 let distribute_mck_define_params (maxpos, minpos) = fun (lop,mop,rop,bop) ->
34e49164 446 fun x ->
ae4735db 447 Visitor_c.vk_define_params_splitted_s
34e49164
C
448 (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
449 x
450
ae4735db 451 let get_pos mck =
34e49164 452 match mck with
951c7801 453 | Ast_cocci.PLUS _ -> raise Impossible
708f4980 454 | Ast_cocci.CONTEXT (Ast_cocci.FixPos (i1,i2),_)
ae4735db 455 | Ast_cocci.MINUS (Ast_cocci.FixPos (i1,i2),_,_,_) ->
34e49164 456 Ast_cocci.FixPos (i1,i2)
708f4980 457 | Ast_cocci.CONTEXT (Ast_cocci.DontCarePos,_)
ae4735db 458 | Ast_cocci.MINUS (Ast_cocci.DontCarePos,_,_,_) ->
34e49164 459 Ast_cocci.DontCarePos
90aeb998 460 | _ -> failwith "weird: dont have position info for the mcodekind 2"
ae4735db
C
461
462 let distrf (ii_of_x_f, distribute_mck_x_f) =
463 fun ia x -> fun tin ->
34e49164
C
464 let mck = Ast_cocci.get_mcodekind ia in
465 let (max, min) = Lib_parsing_c.max_min_by_pos (ii_of_x_f x)
466 in
ae4735db 467 if
34e49164 468 (* bug: check_pos mck max && check_pos mck min
ae4735db 469 *
34e49164
C
470 * if do that then if have - f(...); and in C f(1,2); then we
471 * would get a "already tagged" because the '...' would sucess in
472 * transformaing both '1' and '1,2'. So being in the range is not
ae4735db 473 * enough. We must be equal exactly to the range!
34e49164 474 *)
ae4735db 475 (match get_pos mck with
34e49164 476 | Ast_cocci.DontCarePos -> true
ae4735db 477 | Ast_cocci.FixPos (i1, i2) ->
b1b2de81 478 i1 =*= min && i2 =*= max
34e49164
C
479 | _ -> raise Impossible
480 )
481
ae4735db 482 then
34e49164 483 return (
ae4735db 484 ia,
34e49164
C
485 distribute_mck mck (distribute_mck_x_f (max,min)) x tin
486 ) tin
487 else fail tin
488
489
490 let distrf_e = distrf (Lib_parsing_c.ii_of_expr, distribute_mck_expr)
491 let distrf_args = distrf (Lib_parsing_c.ii_of_args, distribute_mck_args)
492 let distrf_type = distrf (Lib_parsing_c.ii_of_type, distribute_mck_type)
493 let distrf_param = distrf (Lib_parsing_c.ii_of_param, distribute_mck_param)
494 let distrf_params = distrf (Lib_parsing_c.ii_of_params,distribute_mck_params)
495 let distrf_ini = distrf (Lib_parsing_c.ii_of_ini,distribute_mck_ini)
c491d8ee 496 let distrf_inis = distrf (Lib_parsing_c.ii_of_inis,distribute_mck_inis)
413ffc02
C
497 let distrf_decl = distrf (Lib_parsing_c.ii_of_decl,distribute_mck_decl)
498 let distrf_field = distrf (Lib_parsing_c.ii_of_field,distribute_mck_field)
34e49164 499 let distrf_node = distrf (Lib_parsing_c.ii_of_node,distribute_mck_node)
c491d8ee
C
500 let distrf_enum_fields =
501 distrf (Lib_parsing_c.ii_of_enum_fields, distribute_mck_enum_fields)
ae4735db 502 let distrf_struct_fields =
34e49164 503 distrf (Lib_parsing_c.ii_of_struct_fields, distribute_mck_struct_fields)
ae4735db 504 let distrf_cst =
34e49164 505 distrf (Lib_parsing_c.ii_of_cst, distribute_mck_cst)
ae4735db 506 let distrf_define_params =
34e49164
C
507 distrf (Lib_parsing_c.ii_of_define_params,distribute_mck_define_params)
508
509
510 (* ------------------------------------------------------------------------*)
ae4735db 511 (* Environment *)
34e49164 512 (* ------------------------------------------------------------------------*)
ae4735db 513 let meta_name_to_str (s1, s2) = s1 ^ "." ^ s2
34e49164 514
ae4735db 515 let envf keep inherited = fun (s, value, _) f tin ->
34e49164 516 let s = Ast_cocci.unwrap_mcode s in
ae4735db 517 let v =
b1b2de81 518 if keep =*= Type_cocci.Saved
34e49164
C
519 then (
520 try Some (List.assoc s tin.binding)
ae4735db 521 with Not_found ->
34e49164
C
522 pr2(sprintf
523 "Don't find value for metavariable %s in the environment"
524 (meta_name_to_str s));
525 None)
526 else
527 (* not raise Impossible! *)
528 Some (value)
529 in
530 match v with
531 | None -> fail tin
532 | Some (value') ->
533
534 (* Ex: in cocci_vs_c someone wants to add a binding. Here in
ae4735db 535 * transformation3 the value for this var may be already in the
34e49164
C
536 * env, because for instance its value were fixed in a previous
537 * SmPL rule. So here we want to check that this is the same value.
538 * If forget to do the check, what can happen ? Because of Exp
ae4735db 539 * and other disjunctive feature of cocci_vs_c (>||>), we
34e49164
C
540 * may accept a match at a wrong position. Maybe later this
541 * will be detected via the pos system on tokens, but maybe
542 * not. So safer to keep the check.
543 *)
544
545 (*f () tin*)
978fd7e5
C
546 let equal =
547 if inherited
548 then Cocci_vs_c.equal_inh_metavarval
549 else Cocci_vs_c.equal_metavarval in
ae4735db 550 if equal value value'
34e49164
C
551 then f () tin
552 else fail tin
553
ae4735db 554
951c7801
C
555 let check_idconstraint matcher c id = fun f tin -> f () tin
556 let check_constraints_ne matcher constraints exp = fun f tin -> f () tin
34e49164
C
557
558 (* ------------------------------------------------------------------------*)
ae4735db 559 (* Environment, allbounds *)
34e49164
C
560 (* ------------------------------------------------------------------------*)
561 let (all_bound : Ast_cocci.meta_name list -> tin -> bool) = fun l tin ->
562 true (* in transform we don't care ? *)
563
564end
565
566(*****************************************************************************)
ae4735db 567(* Entry point *)
34e49164 568(*****************************************************************************)
485bce71 569module TRANS = Cocci_vs_c.COCCI_VS_C (XTRANS)
34e49164
C
570
571
ae4735db
C
572let transform_re_node a b tin =
573 match TRANS.rule_elem_node a b tin with
34e49164
C
574 | None -> raise Impossible
575 | Some (_sp, b') -> b'
576
34e49164 577let (transform2: string (* rule name *) -> string list (* dropped_isos *) ->
1be43e12 578 Lib_engine.metavars_binding (* inherited bindings *) ->
ae4735db
C
579 Lib_engine.numbered_transformation_info -> F.cflow -> F.cflow) =
580 fun rule_name dropped_isos binding0 xs cflow ->
ae4735db 581 let extra = {
34e49164
C
582 optional_storage_iso = not(List.mem "optional_storage" dropped_isos);
583 optional_qualifier_iso = not(List.mem "optional_qualifier" dropped_isos);
584 value_format_iso = not(List.mem "value_format" dropped_isos);
585 current_rule_name = rule_name;
708f4980 586 index = [];
34e49164
C
587 } in
588
589 (* find the node, transform, update the node, and iter for all elements *)
590
ae4735db 591 xs +> List.fold_left (fun acc (index, (nodei, binding, rule_elem)) ->
34e49164 592 (* subtil: not cflow#nodes but acc#nodes *)
ae4735db 593 let node = acc#nodes#assoc nodei in
34e49164 594
faf9a90c 595 if !Flag.show_transinfo
34e49164 596 then pr2 "transform one node";
708f4980 597
34e49164 598 let tin = {
708f4980 599 XTRANS.extra = {extra with index = index};
1be43e12
C
600 XTRANS.binding = binding0@binding;
601 XTRANS.binding0 = []; (* not used - everything constant for trans *)
34e49164
C
602 } in
603
604 let node' = transform_re_node rule_elem node tin in
605
ae4735db 606 (* assert that have done something. But with metaruleElem sometimes
34e49164
C
607 dont modify fake nodes. So special case before on Fake nodes. *)
608 (match F.unwrap node with
609 | F.Enter | F.Exit | F.ErrorExit
ae4735db 610 | F.EndStatement _ | F.CaseNode _
34e49164 611 | F.Fake
ae4735db 612 | F.TrueNode | F.FalseNode | F.AfterNode | F.FallThroughNode
34e49164
C
613 -> ()
614 | _ -> () (* assert (not (node =*= node')); *)
615 );
616
617 (* useless, we dont go back from flow to ast now *)
618 (* let node' = lastfix_comma_struct node' in *)
ae4735db 619
34e49164
C
620 acc#replace_node (nodei, node');
621 acc
622 ) cflow
623
624
625
ae4735db
C
626let transform a b c d e =
627 Common.profile_code "Transformation3.transform"
1be43e12 628 (fun () -> transform2 a b c d e)