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