Commit | Line | Data |
---|---|---|
f537ebc4 | 1 | (* |
17ba0788 C |
2 | * Copyright 2012, INRIA |
3 | * Julia Lawall, Gilles Muller | |
4 | * Copyright 2010-2011, INRIA, University of Copenhagen | |
f537ebc4 C |
5 | * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix |
6 | * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen | |
7 | * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix | |
8 | * This file is part of Coccinelle. | |
9 | * | |
10 | * Coccinelle is free software: you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation, according to version 2 of the License. | |
13 | * | |
14 | * Coccinelle is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>. | |
21 | * | |
22 | * The authors reserve the right to distribute this or future versions of | |
23 | * Coccinelle under other licenses. | |
24 | *) | |
25 | ||
26 | ||
feec80c3 | 27 | # 0 "./transformation_c.ml" |
34e49164 C |
28 | open Common |
29 | ||
30 | module F = Control_flow_c | |
31 | ||
32 | (*****************************************************************************) | |
ae4735db | 33 | (* The functor argument *) |
34e49164 C |
34 | (*****************************************************************************) |
35 | ||
36 | (* info passed recursively in monad in addition to binding *) | |
ae4735db | 37 | type xinfo = { |
34e49164 C |
38 | optional_storage_iso : bool; |
39 | optional_qualifier_iso : bool; | |
40 | value_format_iso : bool; | |
5427db06 | 41 | optional_declarer_semicolon_iso : bool; |
34e49164 | 42 | current_rule_name : string; (* used for errors *) |
708f4980 | 43 | index : int list (* witness tree indices *) |
34e49164 C |
44 | } |
45 | ||
46 | module XTRANS = struct | |
47 | ||
48 | (* ------------------------------------------------------------------------*) | |
ae4735db | 49 | (* Combinators history *) |
34e49164 C |
50 | (* ------------------------------------------------------------------------*) |
51 | (* | |
ae4735db C |
52 | * version0: |
53 | * type ('a, 'b) transformer = | |
34e49164 | 54 | * 'a -> 'b -> Lib_engine.metavars_binding -> 'b |
ae4735db C |
55 | * exception NoMatch |
56 | * | |
34e49164 | 57 | * version1: |
ae4735db | 58 | * type ('a, 'b) transformer = |
34e49164 | 59 | * 'a -> 'b -> Lib_engine.metavars_binding -> 'b option |
ae4735db C |
60 | * use an exception monad |
61 | * | |
34e49164 C |
62 | * version2: |
63 | * type tin = Lib_engine.metavars_binding | |
64 | *) | |
65 | ||
66 | (* ------------------------------------------------------------------------*) | |
ae4735db | 67 | (* Standard type and operators *) |
34e49164 C |
68 | (* ------------------------------------------------------------------------*) |
69 | ||
ae4735db | 70 | type tin = { |
34e49164 C |
71 | extra: xinfo; |
72 | binding: Lib_engine.metavars_binding; | |
1be43e12 | 73 | binding0: Lib_engine.metavars_binding; (* inherited variable *) |
34e49164 C |
74 | } |
75 | type 'x tout = 'x option | |
76 | ||
77 | type ('a, 'b) matcher = 'a -> 'b -> tin -> ('a * 'b) tout | |
78 | ||
ae4735db | 79 | let (>>=) m f = fun tin -> |
34e49164 C |
80 | match m tin with |
81 | | None -> None | |
82 | | Some (a,b) -> f a b tin | |
83 | ||
ae4735db | 84 | let return = fun x -> fun tin -> |
34e49164 C |
85 | Some x |
86 | ||
87 | (* can have fail in transform now that the process is deterministic ? *) | |
ae4735db | 88 | let fail = fun tin -> |
34e49164 C |
89 | None |
90 | ||
ae4735db | 91 | let (>||>) m1 m2 = fun tin -> |
34e49164 C |
92 | match m1 tin with |
93 | | None -> m2 tin | |
94 | | Some x -> Some x (* stop as soon as have found something *) | |
95 | ||
96 | let (>|+|>) m1 m2 = m1 >||> m2 | |
97 | ||
ae4735db | 98 | let (>&&>) f m = fun tin -> |
34e49164 C |
99 | if f tin then m tin else fail tin |
100 | ||
ae4735db | 101 | let optional_storage_flag f = fun tin -> |
34e49164 C |
102 | f (tin.extra.optional_storage_iso) tin |
103 | ||
ae4735db | 104 | let optional_qualifier_flag f = fun tin -> |
34e49164 C |
105 | f (tin.extra.optional_qualifier_iso) tin |
106 | ||
ae4735db | 107 | let value_format_flag f = fun tin -> |
34e49164 C |
108 | f (tin.extra.value_format_iso) tin |
109 | ||
5427db06 C |
110 | let optional_declarer_semicolon_flag f = fun tin -> |
111 | f (tin.extra.optional_declarer_semicolon_iso) tin | |
112 | ||
485bce71 | 113 | let mode = Cocci_vs_c.TransformMode |
34e49164 | 114 | |
993936c0 C |
115 | (* ------------------------------------------------------------------------*) |
116 | (* Env *) | |
117 | (* ------------------------------------------------------------------------*) | |
118 | ||
119 | (* When env is used in + code, have to strip it more to avoid circular | |
120 | references due to local variable information *) | |
121 | ||
122 | let clean_env env = | |
123 | List.map | |
124 | (function (v,vl) -> | |
125 | match vl with | |
126 | | Ast_c.MetaExprVal(e,ml) -> | |
127 | (v,Ast_c.MetaExprVal(Lib_parsing_c.real_al_expr e,ml)) | |
128 | | Ast_c.MetaExprListVal(es) -> | |
129 | (v,Ast_c.MetaExprListVal(Lib_parsing_c.real_al_arguments es)) | |
130 | | Ast_c.MetaTypeVal(ty) -> | |
131 | (v,Ast_c.MetaTypeVal(Lib_parsing_c.real_al_type ty)) | |
132 | | Ast_c.MetaInitVal(i) -> | |
133 | (v,Ast_c.MetaInitVal(Lib_parsing_c.real_al_init i)) | |
134 | | Ast_c.MetaInitListVal(is) -> | |
135 | (v,Ast_c.MetaInitListVal(Lib_parsing_c.real_al_inits is)) | |
136 | | Ast_c.MetaDeclVal(d) -> | |
137 | (v,Ast_c.MetaDeclVal(Lib_parsing_c.real_al_decl d)) | |
138 | | Ast_c.MetaStmtVal(s) -> | |
139 | (v,Ast_c.MetaStmtVal(Lib_parsing_c.real_al_statement s)) | |
140 | | _ -> (v,vl)) | |
141 | env | |
142 | ||
143 | ||
34e49164 | 144 | (* ------------------------------------------------------------------------*) |
ae4735db | 145 | (* Exp *) |
34e49164 | 146 | (* ------------------------------------------------------------------------*) |
ae4735db | 147 | let cocciExp = fun expf expa node -> fun tin -> |
34e49164 | 148 | |
ae4735db C |
149 | let bigf = { |
150 | Visitor_c.default_visitor_c_s with | |
34e49164 C |
151 | Visitor_c.kexpr_s = (fun (k, bigf) expb -> |
152 | match expf expa expb tin with | |
153 | | None -> (* failed *) k expb | |
154 | | Some (x, expb) -> expb); | |
155 | } | |
156 | in | |
157 | Some (expa, Visitor_c.vk_node_s bigf node) | |
158 | ||
159 | ||
160 | (* same as cocciExp, but for expressions in an expression, not expressions | |
161 | in a node *) | |
ae4735db | 162 | let cocciExpExp = fun expf expa expb -> fun tin -> |
34e49164 | 163 | |
ae4735db C |
164 | let bigf = { |
165 | Visitor_c.default_visitor_c_s with | |
34e49164 C |
166 | Visitor_c.kexpr_s = (fun (k, bigf) expb -> |
167 | match expf expa expb tin with | |
168 | | None -> (* failed *) k expb | |
169 | | Some (x, expb) -> expb); | |
170 | } | |
171 | in | |
172 | Some (expa, Visitor_c.vk_expr_s bigf expb) | |
173 | ||
174 | ||
ae4735db | 175 | let cocciTy = fun expf expa node -> fun tin -> |
34e49164 | 176 | |
ae4735db C |
177 | let bigf = { |
178 | Visitor_c.default_visitor_c_s with | |
34e49164 C |
179 | Visitor_c.ktype_s = (fun (k, bigf) expb -> |
180 | match expf expa expb tin with | |
181 | | None -> (* failed *) k expb | |
182 | | Some (x, expb) -> expb); | |
183 | } | |
184 | in | |
185 | Some (expa, Visitor_c.vk_node_s bigf node) | |
186 | ||
ae4735db | 187 | let cocciInit = fun expf expa node -> fun tin -> |
1be43e12 | 188 | |
ae4735db C |
189 | let bigf = { |
190 | Visitor_c.default_visitor_c_s with | |
1be43e12 C |
191 | Visitor_c.kini_s = (fun (k, bigf) expb -> |
192 | match expf expa expb tin with | |
193 | | None -> (* failed *) k expb | |
194 | | Some (x, expb) -> expb); | |
195 | } | |
196 | in | |
197 | Some (expa, Visitor_c.vk_node_s bigf node) | |
198 | ||
34e49164 C |
199 | |
200 | (* ------------------------------------------------------------------------*) | |
ae4735db | 201 | (* Tokens *) |
34e49164 | 202 | (* ------------------------------------------------------------------------*) |
ae4735db | 203 | let check_pos info mck pos = |
34e49164 | 204 | match mck with |
951c7801 | 205 | | Ast_cocci.PLUS _ -> raise Impossible |
708f4980 | 206 | | Ast_cocci.CONTEXT (Ast_cocci.FixPos (i1,i2),_) |
ae4735db | 207 | | Ast_cocci.MINUS (Ast_cocci.FixPos (i1,i2),_,_,_) -> |
34e49164 | 208 | pos <= i2 && pos >= i1 |
708f4980 | 209 | | Ast_cocci.CONTEXT (Ast_cocci.DontCarePos,_) |
ae4735db | 210 | | Ast_cocci.MINUS (Ast_cocci.DontCarePos,_,_,_) -> |
34e49164 C |
211 | true |
212 | | _ -> | |
213 | match info with | |
214 | Some info -> | |
215 | failwith | |
216 | (Printf.sprintf | |
0708f913 | 217 | "weird: dont have position info for the mcodekind in line %d column %d" |
34e49164 C |
218 | info.Ast_cocci.line info.Ast_cocci.column) |
219 | | None -> | |
0708f913 | 220 | failwith "weird: dont have position info for the mcodekind" |
34e49164 | 221 | |
97111a47 C |
222 | (* these remove constraints, at least those that contain pcre regexps, |
223 | which cannot be compared (problem in the unparser) *) | |
224 | let strip_anything anything = | |
225 | let donothing r k e = k e in | |
226 | let mcode mc = mc in | |
227 | let ident r k e = | |
228 | let e = k e in | |
229 | match Ast_cocci.unwrap e with | |
230 | Ast_cocci.MetaId(name,constraints,u,i) -> | |
231 | Ast_cocci.rewrap e | |
232 | (Ast_cocci.MetaId(name,Ast_cocci.IdNoConstraint,u,i)) | |
233 | | Ast_cocci.MetaFunc(name,constraints,u,i) -> | |
234 | Ast_cocci.rewrap e | |
235 | (Ast_cocci.MetaFunc(name,Ast_cocci.IdNoConstraint,u,i)) | |
236 | | Ast_cocci.MetaLocalFunc(name,constraints,u,i) -> | |
237 | Ast_cocci.rewrap e | |
238 | (Ast_cocci.MetaLocalFunc(name,Ast_cocci.IdNoConstraint,u,i)) | |
239 | | _ -> e in | |
240 | let expression r k e = | |
241 | let e = k e in | |
242 | match Ast_cocci.unwrap e with | |
243 | Ast_cocci.MetaErr(name,constraints,u,i) -> | |
244 | Ast_cocci.rewrap e | |
245 | (Ast_cocci.MetaErr(name,Ast_cocci.NoConstraint,u,i)) | |
246 | | Ast_cocci.MetaExpr(name,constraints,u,ty,form,i) -> | |
247 | Ast_cocci.rewrap e | |
248 | (Ast_cocci.MetaExpr(name,Ast_cocci.NoConstraint,u,ty,form,i)) | |
249 | | _ -> e in | |
250 | let fn = Visitor_ast.rebuilder | |
251 | mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode | |
252 | donothing donothing donothing donothing donothing | |
253 | ident expression donothing donothing donothing donothing | |
254 | donothing donothing donothing donothing donothing donothing in | |
255 | ||
256 | fn.Visitor_ast.rebuilder_anything anything | |
257 | ||
258 | let strip_minus_code = function | |
259 | Ast_cocci.REPLACEMENT(l,c) -> | |
260 | Ast_cocci.REPLACEMENT(List.map (List.map strip_anything) l,c) | |
261 | | Ast_cocci.NOREPLACEMENT -> Ast_cocci.NOREPLACEMENT | |
262 | let strip_context_code = function | |
263 | Ast_cocci.BEFORE(l,c) -> | |
264 | Ast_cocci.BEFORE(List.map (List.map strip_anything) l,c) | |
265 | | Ast_cocci.AFTER(l,c) -> | |
266 | Ast_cocci.AFTER(List.map (List.map strip_anything) l,c) | |
267 | | Ast_cocci.BEFOREAFTER(l1,l2,c) -> | |
268 | Ast_cocci.BEFOREAFTER(List.map (List.map strip_anything) l1, | |
269 | List.map (List.map strip_anything) l2,c) | |
270 | | Ast_cocci.NOTHING -> Ast_cocci.NOTHING | |
271 | let strip_mck_code = function | |
272 | Ast_cocci.MINUS(p,l,a,repl) -> | |
273 | Ast_cocci.MINUS(p,l,a,strip_minus_code repl) | |
274 | | Ast_cocci.CONTEXT(p,ba) -> Ast_cocci.CONTEXT(p,strip_context_code ba) | |
275 | | Ast_cocci.PLUS(c) -> Ast_cocci.PLUS(c) | |
34e49164 | 276 | |
ae4735db | 277 | let tag_with_mck mck ib = fun tin -> |
34e49164 C |
278 | |
279 | let cocciinforef = ib.Ast_c.cocci_tag in | |
951c7801 | 280 | let (oldmcode, oldenvs) = Ast_c.mcode_and_env_of_cocciref cocciinforef in |
34e49164 C |
281 | |
282 | let mck = | |
ae4735db | 283 | (* coccionly: |
34e49164 C |
284 | if !Flag_parsing_cocci.sgrep_mode |
285 | then Sgrep.process_sgrep ib mck | |
ae4735db | 286 | else |
485bce71 | 287 | *) |
ae4735db | 288 | mck |
34e49164 C |
289 | in |
290 | (match mck, Ast_c.pinfo_of_info ib with | |
291 | | _, Ast_c.AbstractLineTok _ -> raise Impossible | |
ae4735db | 292 | | Ast_cocci.MINUS(_), Ast_c.ExpandedTok _ -> |
6756e19d C |
293 | failwith |
294 | (Printf.sprintf | |
295 | "%s: %d: try to delete an expanded token: %s" | |
296 | (Ast_c.file_of_info ib) | |
297 | (Ast_c.line_of_info ib) (Ast_c.str_of_info ib)) | |
34e49164 C |
298 | | _ -> () |
299 | ); | |
300 | ||
8babbc8f | 301 | let many_context_count = function |
951c7801 C |
302 | Ast_cocci.BEFORE(_,Ast_cocci.MANY) | Ast_cocci.AFTER(_,Ast_cocci.MANY) |
303 | | Ast_cocci.BEFOREAFTER(_,_,Ast_cocci.MANY) -> true | |
304 | | _ -> false in | |
305 | ||
8babbc8f C |
306 | let many_minus_count = function |
307 | Ast_cocci.REPLACEMENT(_,Ast_cocci.MANY) -> true | |
308 | | _ -> false in | |
309 | ||
951c7801 C |
310 | (match (oldmcode,mck) with |
311 | | (Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING), _) -> | |
312 | (* nothing there, so take the new stuff *) | |
708f4980 C |
313 | let update_inst inst = function |
314 | Ast_cocci.MINUS (pos,_,adj,any_xxs) -> | |
315 | Ast_cocci.MINUS (pos,inst,adj,any_xxs) | |
316 | | mck -> mck in | |
97111a47 | 317 | let mck = strip_mck_code (update_inst tin.extra.index mck) in |
993936c0 C |
318 | (* clean_env actually only needed if there is an addition |
319 | not sure the extra efficiency would be worth duplicating the code *) | |
320 | cocciinforef := | |
97111a47 | 321 | Some (mck, [clean_env tin.binding]) |
951c7801 C |
322 | | (_, Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING)) -> |
323 | (* can this case occur? stay with the old stuff *) | |
324 | () | |
8babbc8f C |
325 | | (Ast_cocci.MINUS(old_pos,old_inst,old_adj,Ast_cocci.NOREPLACEMENT), |
326 | Ast_cocci.MINUS(new_pos,new_inst,new_adj,Ast_cocci.NOREPLACEMENT)) | |
327 | when old_pos = new_pos | |
328 | (* not sure why the following condition is useful. | |
329 | should be ok to double remove even if the environments are | |
330 | different *) | |
331 | (* && | |
332 | (List.mem tin.binding oldenvs or !Flag.sgrep_mode2) *) | |
708f4980 C |
333 | (* no way to combine adjacency information, just drop one *) |
334 | -> | |
335 | cocciinforef := Some | |
336 | (Ast_cocci.MINUS | |
8babbc8f C |
337 | (old_pos,Common.union_set old_inst new_inst,old_adj, |
338 | Ast_cocci.NOREPLACEMENT), | |
951c7801 | 339 | [tin.binding]); |
708f4980 | 340 | (if !Flag_matcher.show_misc |
8babbc8f C |
341 | then pr2_once "already tagged but only removed, so safe") |
342 | ||
343 | (* ++ cases *) | |
344 | | (Ast_cocci.MINUS(old_pos,old_inst,old_adj,old_modif), | |
345 | Ast_cocci.MINUS(new_pos,new_inst,new_adj,new_modif)) | |
346 | when old_pos = new_pos && | |
97111a47 C |
347 | old_modif = strip_minus_code new_modif && |
348 | many_minus_count old_modif -> | |
8babbc8f C |
349 | |
350 | cocciinforef := | |
351 | Some(Ast_cocci.MINUS(old_pos,Common.union_set old_inst new_inst, | |
352 | old_adj,old_modif), | |
993936c0 | 353 | (clean_env tin.binding)::oldenvs) |
951c7801 C |
354 | |
355 | | (Ast_cocci.CONTEXT(old_pos,old_modif), | |
356 | Ast_cocci.CONTEXT(new_pos,new_modif)) | |
357 | when old_pos = new_pos && | |
97111a47 C |
358 | old_modif = strip_context_code new_modif && |
359 | many_context_count old_modif -> | |
951c7801 C |
360 | (* iteration only allowed on context; no way to replace something |
361 | more than once; now no need for iterable; just check a flag *) | |
362 | ||
363 | cocciinforef := | |
993936c0 C |
364 | Some(Ast_cocci.CONTEXT(old_pos,old_modif), |
365 | (clean_env tin.binding)::oldenvs) | |
708f4980 | 366 | |
ae4735db C |
367 | | _ -> |
368 | (* coccionly: | |
34e49164 C |
369 | if !Flag.sgrep_mode2 |
370 | then ib (* safe *) | |
ae4735db | 371 | else |
485bce71 C |
372 | *) |
373 | begin | |
ae4735db | 374 | (* coccionly: |
708f4980 C |
375 | pad: if dont want cocci write: |
376 | failwith | |
b1b2de81 C |
377 | (match Ast_c.pinfo_of_info ib with |
378 | Ast_c.FakeTok _ -> "already tagged fake token" | |
708f4980 C |
379 | *) |
380 | let pm str mcode env = | |
381 | Printf.sprintf | |
951c7801 | 382 | "%s modification:\n%s\nAccording to environment %d:\n%s\n" |
708f4980 C |
383 | str |
384 | (Common.format_to_string | |
385 | (function _ -> | |
386 | Pretty_print_cocci.print_mcodekind mcode)) | |
951c7801 | 387 | (List.length env) |
708f4980 C |
388 | (String.concat "\n" |
389 | (List.map | |
390 | (function ((r,vr),vl) -> | |
391 | Printf.sprintf " %s.%s -> %s" r vr | |
392 | (Common.format_to_string | |
393 | (function _ -> | |
394 | Pretty_print_engine.pp_binding_kind vl))) | |
395 | env)) in | |
396 | flush stdout; flush stderr; | |
397 | Common.pr2 | |
951c7801 C |
398 | ("\n"^ (String.concat "\n" |
399 | (List.map (pm "previous" oldmcode) oldenvs)) ^ "\n" | |
400 | ^ (pm "current" mck tin.binding)); | |
708f4980 C |
401 | failwith |
402 | (match Ast_c.pinfo_of_info ib with | |
403 | Ast_c.FakeTok _ -> | |
404 | Common.sprintf "%s: already tagged fake token\n" | |
405 | tin.extra.current_rule_name | |
b1b2de81 | 406 | | _ -> |
708f4980 C |
407 | Printf.sprintf |
408 | "%s: already tagged token:\nC code context\n%s" | |
b1b2de81 C |
409 | tin.extra.current_rule_name |
410 | (Common.error_message (Ast_c.file_of_info ib) | |
411 | (Ast_c.str_of_info ib, Ast_c.opos_of_info ib))) | |
951c7801 C |
412 | end); |
413 | ib | |
34e49164 | 414 | |
ae4735db | 415 | let tokenf ia ib = fun tin -> |
34e49164 C |
416 | let (_,i,mck,_) = ia in |
417 | let pos = Ast_c.info_to_fixpos ib in | |
ae4735db | 418 | if check_pos (Some i) mck pos |
34e49164 C |
419 | then return (ia, tag_with_mck mck ib tin) tin |
420 | else fail tin | |
421 | ||
ae4735db | 422 | let tokenf_mck mck ib = fun tin -> |
34e49164 | 423 | let pos = Ast_c.info_to_fixpos ib in |
ae4735db | 424 | if check_pos None mck pos |
34e49164 C |
425 | then return (mck, tag_with_mck mck ib tin) tin |
426 | else fail tin | |
427 | ||
428 | ||
429 | (* ------------------------------------------------------------------------*) | |
ae4735db | 430 | (* Distribute mcode *) |
34e49164 C |
431 | (* ------------------------------------------------------------------------*) |
432 | ||
433 | (* When in the SP we attach something to a metavariable, or delete it, as in | |
434 | * - S | |
435 | * + foo(); | |
ae4735db C |
436 | * we have to minusize all the token that compose S in the C code, and |
437 | * attach the 'foo();' to the right token, the one at the very right. | |
34e49164 C |
438 | *) |
439 | ||
ae4735db | 440 | type 'a distributer = |
34e49164 C |
441 | (Ast_c.info -> Ast_c.info) * (* what to do on left *) |
442 | (Ast_c.info -> Ast_c.info) * (* what to do on middle *) | |
443 | (Ast_c.info -> Ast_c.info) * (* what to do on right *) | |
444 | (Ast_c.info -> Ast_c.info) -> (* what to do on both *) | |
445 | 'a -> 'a | |
446 | ||
447 | let distribute_mck mcodekind distributef expr tin = | |
448 | match mcodekind with | |
ae4735db | 449 | | Ast_cocci.MINUS (pos,_,adj,any_xxs) -> |
708f4980 | 450 | let inst = tin.extra.index in |
34e49164 | 451 | distributef ( |
708f4980 C |
452 | (fun ib -> |
453 | tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,any_xxs)) ib tin), | |
454 | (fun ib -> | |
8babbc8f C |
455 | tag_with_mck |
456 | (Ast_cocci.MINUS (pos,inst,adj,Ast_cocci.NOREPLACEMENT)) ib tin), | |
708f4980 | 457 | (fun ib -> |
8babbc8f C |
458 | tag_with_mck |
459 | (Ast_cocci.MINUS (pos,inst,adj,Ast_cocci.NOREPLACEMENT)) ib tin), | |
708f4980 C |
460 | (fun ib -> |
461 | tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,any_xxs)) ib tin) | |
34e49164 | 462 | ) expr |
ae4735db | 463 | | Ast_cocci.CONTEXT (pos,any_befaft) -> |
34e49164 C |
464 | (match any_befaft with |
465 | | Ast_cocci.NOTHING -> expr | |
ae4735db C |
466 | |
467 | | Ast_cocci.BEFORE (xxs,c) -> | |
34e49164 | 468 | distributef ( |
ae4735db | 469 | (fun ib -> tag_with_mck |
951c7801 | 470 | (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE (xxs,c))) ib tin), |
ae4735db C |
471 | (fun x -> x), |
472 | (fun x -> x), | |
473 | (fun ib -> tag_with_mck | |
951c7801 | 474 | (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE (xxs,c))) ib tin) |
34e49164 | 475 | ) expr |
ae4735db | 476 | | Ast_cocci.AFTER (xxs,c) -> |
34e49164 | 477 | distributef ( |
ae4735db C |
478 | (fun x -> x), |
479 | (fun x -> x), | |
480 | (fun ib -> tag_with_mck | |
951c7801 | 481 | (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER (xxs,c))) ib tin), |
ae4735db | 482 | (fun ib -> tag_with_mck |
951c7801 | 483 | (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER (xxs,c))) ib tin) |
34e49164 C |
484 | ) expr |
485 | ||
ae4735db | 486 | | Ast_cocci.BEFOREAFTER (xxs, yys, c) -> |
34e49164 | 487 | distributef ( |
ae4735db | 488 | (fun ib -> tag_with_mck |
951c7801 | 489 | (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE (xxs,c))) ib tin), |
ae4735db C |
490 | (fun x -> x), |
491 | (fun ib -> tag_with_mck | |
951c7801 | 492 | (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER (yys,c))) ib tin), |
ae4735db | 493 | (fun ib -> tag_with_mck |
951c7801 | 494 | (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFOREAFTER (xxs,yys,c))) |
34e49164 C |
495 | ib tin) |
496 | ) expr | |
497 | ||
498 | ) | |
951c7801 | 499 | | Ast_cocci.PLUS _ -> raise Impossible |
34e49164 C |
500 | |
501 | ||
502 | (* use new strategy, collect ii, sort, recollect and tag *) | |
503 | ||
ae4735db C |
504 | let mk_bigf (maxpos, minpos) (lop,mop,rop,bop) = |
505 | let bigf = { | |
34e49164 | 506 | Visitor_c.default_visitor_c_s with |
ae4735db | 507 | Visitor_c.kinfo_s = (fun (k,bigf) i -> |
34e49164 C |
508 | let pos = Ast_c.info_to_fixpos i in |
509 | match () with | |
510 | | _ when Ast_cocci.equal_pos pos maxpos && | |
511 | Ast_cocci.equal_pos pos minpos -> bop i | |
512 | | _ when Ast_cocci.equal_pos pos maxpos -> rop i | |
513 | | _ when Ast_cocci.equal_pos pos minpos -> lop i | |
514 | | _ -> mop i | |
515 | ) | |
516 | } in | |
517 | bigf | |
518 | ||
519 | let distribute_mck_expr (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
520 | Visitor_c.vk_expr_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
521 | ||
522 | let distribute_mck_args (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
523 | Visitor_c.vk_args_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
524 | ||
525 | let distribute_mck_type (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
526 | Visitor_c.vk_type_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
527 | ||
413ffc02 C |
528 | let distribute_mck_decl (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> |
529 | Visitor_c.vk_decl_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
530 | ||
531 | let distribute_mck_field (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
532 | Visitor_c.vk_struct_field_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
533 | ||
34e49164 C |
534 | let distribute_mck_ini (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> |
535 | Visitor_c.vk_ini_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
536 | ||
c491d8ee C |
537 | let distribute_mck_inis (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> |
538 | Visitor_c.vk_inis_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
539 | ||
34e49164 C |
540 | let distribute_mck_param (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> |
541 | Visitor_c.vk_param_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
542 | ||
543 | let distribute_mck_params (maxpos, minpos) = fun (lop,mop,rop,bop) ->fun x -> | |
544 | Visitor_c.vk_params_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
545 | x | |
546 | ||
547 | let distribute_mck_node (maxpos, minpos) = fun (lop,mop,rop,bop) ->fun x -> | |
548 | Visitor_c.vk_node_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
549 | x | |
550 | ||
c491d8ee C |
551 | let distribute_mck_enum_fields (maxpos, minpos) = |
552 | fun (lop,mop,rop,bop) ->fun x -> | |
553 | Visitor_c.vk_enum_fields_splitted_s | |
554 | (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
555 | x | |
556 | ||
ae4735db | 557 | let distribute_mck_struct_fields (maxpos, minpos) = |
34e49164 C |
558 | fun (lop,mop,rop,bop) ->fun x -> |
559 | Visitor_c.vk_struct_fields_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
560 | x | |
561 | ||
ae4735db | 562 | let distribute_mck_cst (maxpos, minpos) = |
34e49164 C |
563 | fun (lop,mop,rop,bop) ->fun x -> |
564 | Visitor_c.vk_cst_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
565 | x | |
566 | ||
567 | ||
ae4735db | 568 | let distribute_mck_define_params (maxpos, minpos) = fun (lop,mop,rop,bop) -> |
34e49164 | 569 | fun x -> |
ae4735db | 570 | Visitor_c.vk_define_params_splitted_s |
34e49164 C |
571 | (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) |
572 | x | |
573 | ||
ae4735db | 574 | let get_pos mck = |
34e49164 | 575 | match mck with |
951c7801 | 576 | | Ast_cocci.PLUS _ -> raise Impossible |
708f4980 | 577 | | Ast_cocci.CONTEXT (Ast_cocci.FixPos (i1,i2),_) |
ae4735db | 578 | | Ast_cocci.MINUS (Ast_cocci.FixPos (i1,i2),_,_,_) -> |
34e49164 | 579 | Ast_cocci.FixPos (i1,i2) |
708f4980 | 580 | | Ast_cocci.CONTEXT (Ast_cocci.DontCarePos,_) |
ae4735db | 581 | | Ast_cocci.MINUS (Ast_cocci.DontCarePos,_,_,_) -> |
34e49164 | 582 | Ast_cocci.DontCarePos |
90aeb998 | 583 | | _ -> failwith "weird: dont have position info for the mcodekind 2" |
ae4735db C |
584 | |
585 | let distrf (ii_of_x_f, distribute_mck_x_f) = | |
586 | fun ia x -> fun tin -> | |
34e49164 C |
587 | let mck = Ast_cocci.get_mcodekind ia in |
588 | let (max, min) = Lib_parsing_c.max_min_by_pos (ii_of_x_f x) | |
589 | in | |
ae4735db | 590 | if |
34e49164 | 591 | (* bug: check_pos mck max && check_pos mck min |
ae4735db | 592 | * |
34e49164 C |
593 | * if do that then if have - f(...); and in C f(1,2); then we |
594 | * would get a "already tagged" because the '...' would sucess in | |
595 | * transformaing both '1' and '1,2'. So being in the range is not | |
ae4735db | 596 | * enough. We must be equal exactly to the range! |
34e49164 | 597 | *) |
ae4735db | 598 | (match get_pos mck with |
34e49164 | 599 | | Ast_cocci.DontCarePos -> true |
ae4735db | 600 | | Ast_cocci.FixPos (i1, i2) -> |
b1b2de81 | 601 | i1 =*= min && i2 =*= max |
34e49164 C |
602 | | _ -> raise Impossible |
603 | ) | |
604 | ||
ae4735db | 605 | then |
34e49164 | 606 | return ( |
ae4735db | 607 | ia, |
34e49164 C |
608 | distribute_mck mck (distribute_mck_x_f (max,min)) x tin |
609 | ) tin | |
610 | else fail tin | |
611 | ||
612 | ||
613 | let distrf_e = distrf (Lib_parsing_c.ii_of_expr, distribute_mck_expr) | |
614 | let distrf_args = distrf (Lib_parsing_c.ii_of_args, distribute_mck_args) | |
615 | let distrf_type = distrf (Lib_parsing_c.ii_of_type, distribute_mck_type) | |
616 | let distrf_param = distrf (Lib_parsing_c.ii_of_param, distribute_mck_param) | |
617 | let distrf_params = distrf (Lib_parsing_c.ii_of_params,distribute_mck_params) | |
618 | let distrf_ini = distrf (Lib_parsing_c.ii_of_ini,distribute_mck_ini) | |
c491d8ee | 619 | let distrf_inis = distrf (Lib_parsing_c.ii_of_inis,distribute_mck_inis) |
413ffc02 C |
620 | let distrf_decl = distrf (Lib_parsing_c.ii_of_decl,distribute_mck_decl) |
621 | let distrf_field = distrf (Lib_parsing_c.ii_of_field,distribute_mck_field) | |
34e49164 | 622 | let distrf_node = distrf (Lib_parsing_c.ii_of_node,distribute_mck_node) |
c491d8ee C |
623 | let distrf_enum_fields = |
624 | distrf (Lib_parsing_c.ii_of_enum_fields, distribute_mck_enum_fields) | |
ae4735db | 625 | let distrf_struct_fields = |
34e49164 | 626 | distrf (Lib_parsing_c.ii_of_struct_fields, distribute_mck_struct_fields) |
ae4735db | 627 | let distrf_cst = |
34e49164 | 628 | distrf (Lib_parsing_c.ii_of_cst, distribute_mck_cst) |
ae4735db | 629 | let distrf_define_params = |
34e49164 C |
630 | distrf (Lib_parsing_c.ii_of_define_params,distribute_mck_define_params) |
631 | ||
632 | ||
633 | (* ------------------------------------------------------------------------*) | |
ae4735db | 634 | (* Environment *) |
34e49164 | 635 | (* ------------------------------------------------------------------------*) |
ae4735db | 636 | let meta_name_to_str (s1, s2) = s1 ^ "." ^ s2 |
34e49164 | 637 | |
ae4735db | 638 | let envf keep inherited = fun (s, value, _) f tin -> |
34e49164 | 639 | let s = Ast_cocci.unwrap_mcode s in |
ae4735db | 640 | let v = |
b1b2de81 | 641 | if keep =*= Type_cocci.Saved |
34e49164 C |
642 | then ( |
643 | try Some (List.assoc s tin.binding) | |
ae4735db | 644 | with Not_found -> |
34e49164 C |
645 | pr2(sprintf |
646 | "Don't find value for metavariable %s in the environment" | |
647 | (meta_name_to_str s)); | |
648 | None) | |
649 | else | |
650 | (* not raise Impossible! *) | |
651 | Some (value) | |
652 | in | |
653 | match v with | |
654 | | None -> fail tin | |
655 | | Some (value') -> | |
656 | ||
657 | (* Ex: in cocci_vs_c someone wants to add a binding. Here in | |
ae4735db | 658 | * transformation3 the value for this var may be already in the |
34e49164 C |
659 | * env, because for instance its value were fixed in a previous |
660 | * SmPL rule. So here we want to check that this is the same value. | |
661 | * If forget to do the check, what can happen ? Because of Exp | |
ae4735db | 662 | * and other disjunctive feature of cocci_vs_c (>||>), we |
34e49164 C |
663 | * may accept a match at a wrong position. Maybe later this |
664 | * will be detected via the pos system on tokens, but maybe | |
665 | * not. So safer to keep the check. | |
666 | *) | |
667 | ||
668 | (*f () tin*) | |
978fd7e5 C |
669 | let equal = |
670 | if inherited | |
671 | then Cocci_vs_c.equal_inh_metavarval | |
672 | else Cocci_vs_c.equal_metavarval in | |
ae4735db | 673 | if equal value value' |
34e49164 C |
674 | then f () tin |
675 | else fail tin | |
676 | ||
ae4735db | 677 | |
951c7801 C |
678 | let check_idconstraint matcher c id = fun f tin -> f () tin |
679 | let check_constraints_ne matcher constraints exp = fun f tin -> f () tin | |
34e49164 C |
680 | |
681 | (* ------------------------------------------------------------------------*) | |
ae4735db | 682 | (* Environment, allbounds *) |
34e49164 C |
683 | (* ------------------------------------------------------------------------*) |
684 | let (all_bound : Ast_cocci.meta_name list -> tin -> bool) = fun l tin -> | |
685 | true (* in transform we don't care ? *) | |
686 | ||
687 | end | |
688 | ||
689 | (*****************************************************************************) | |
ae4735db | 690 | (* Entry point *) |
34e49164 | 691 | (*****************************************************************************) |
485bce71 | 692 | module TRANS = Cocci_vs_c.COCCI_VS_C (XTRANS) |
34e49164 C |
693 | |
694 | ||
ae4735db C |
695 | let transform_re_node a b tin = |
696 | match TRANS.rule_elem_node a b tin with | |
34e49164 C |
697 | | None -> raise Impossible |
698 | | Some (_sp, b') -> b' | |
699 | ||
34e49164 | 700 | let (transform2: string (* rule name *) -> string list (* dropped_isos *) -> |
1be43e12 | 701 | Lib_engine.metavars_binding (* inherited bindings *) -> |
ae4735db C |
702 | Lib_engine.numbered_transformation_info -> F.cflow -> F.cflow) = |
703 | fun rule_name dropped_isos binding0 xs cflow -> | |
ae4735db | 704 | let extra = { |
34e49164 C |
705 | optional_storage_iso = not(List.mem "optional_storage" dropped_isos); |
706 | optional_qualifier_iso = not(List.mem "optional_qualifier" dropped_isos); | |
707 | value_format_iso = not(List.mem "value_format" dropped_isos); | |
5427db06 C |
708 | optional_declarer_semicolon_iso = |
709 | not(List.mem "optional_declarer_semicolon" dropped_isos); | |
34e49164 | 710 | current_rule_name = rule_name; |
708f4980 | 711 | index = []; |
34e49164 C |
712 | } in |
713 | ||
714 | (* find the node, transform, update the node, and iter for all elements *) | |
715 | ||
ae4735db | 716 | xs +> List.fold_left (fun acc (index, (nodei, binding, rule_elem)) -> |
34e49164 | 717 | (* subtil: not cflow#nodes but acc#nodes *) |
ae4735db | 718 | let node = acc#nodes#assoc nodei in |
34e49164 | 719 | |
faf9a90c | 720 | if !Flag.show_transinfo |
993936c0 | 721 | then pr2 (Printf.sprintf "transform one node: %d" nodei); |
708f4980 | 722 | |
34e49164 | 723 | let tin = { |
708f4980 | 724 | XTRANS.extra = {extra with index = index}; |
1be43e12 C |
725 | XTRANS.binding = binding0@binding; |
726 | XTRANS.binding0 = []; (* not used - everything constant for trans *) | |
34e49164 C |
727 | } in |
728 | ||
729 | let node' = transform_re_node rule_elem node tin in | |
730 | ||
ae4735db | 731 | (* assert that have done something. But with metaruleElem sometimes |
34e49164 C |
732 | dont modify fake nodes. So special case before on Fake nodes. *) |
733 | (match F.unwrap node with | |
734 | | F.Enter | F.Exit | F.ErrorExit | |
ae4735db | 735 | | F.EndStatement _ | F.CaseNode _ |
34e49164 | 736 | | F.Fake |
ae4735db | 737 | | F.TrueNode | F.FalseNode | F.AfterNode | F.FallThroughNode |
34e49164 C |
738 | -> () |
739 | | _ -> () (* assert (not (node =*= node')); *) | |
740 | ); | |
741 | ||
742 | (* useless, we dont go back from flow to ast now *) | |
743 | (* let node' = lastfix_comma_struct node' in *) | |
ae4735db | 744 | |
34e49164 C |
745 | acc#replace_node (nodei, node'); |
746 | acc | |
747 | ) cflow | |
748 | ||
749 | ||
750 | ||
ae4735db C |
751 | let transform a b c d e = |
752 | Common.profile_code "Transformation3.transform" | |
1be43e12 | 753 | (fun () -> transform2 a b c d e) |