Release coccinelle-0.2.3rc4
[bpt/coccinelle.git] / parsing_cocci / single_statement.ml
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
25 (* detect statements that are between dots in the minus code, because they
26 may need a special treatment if they are if branches *)
27
28 module Ast0 = Ast0_cocci
29 module Ast = Ast_cocci
30 module V0 = Visitor_ast0
31 module VT0 = Visitor_ast0_types
32
33 (* --------------------------------------------------------------------- *)
34 (* --------------------------------------------------------------------- *)
35 (* Helpers *)
36
37 let left_dots f l =
38 match Ast0.undots l with
39 [] -> false
40 | x::xs -> f x
41
42 let right_dots f l =
43 match List.rev (Ast0.undots l) with
44 [] -> false
45 | x::xs -> f x
46
47 let modif_before_mcode mc =
48 match Ast0.get_mcode_mcodekind mc with
49 Ast0.MINUS mc -> true (*conservative; don't want to hunt right for + code*)
50 | Ast0.PLUS _ -> failwith "not possible"
51 | Ast0.CONTEXT mc ->
52 (match !mc with
53 (Ast.BEFORE _,_,_) -> true
54 | (Ast.BEFOREAFTER _,_,_) -> true
55 | _ -> false)
56 | Ast0.MIXED mc -> true (* don't think mcode can be mixed *)
57
58 let modif_after_mcodekind = function
59 Ast0.MINUS mc -> true (*conservative; don't want to hunt right for + code*)
60 | Ast0.PLUS _ -> failwith "not possible"
61 | Ast0.CONTEXT mc ->
62 (match !mc with
63 (Ast.AFTER _,_,_) -> true
64 | (Ast.BEFOREAFTER _,_,_) -> true
65 | _ -> false)
66 | Ast0.MIXED mc -> true (* don't think mcode can be mixed *)
67
68 let modif_after_mcode mc = modif_after_mcodekind (Ast0.get_mcode_mcodekind mc)
69
70 let any_statements =
71 List.exists
72 (List.exists
73 (function
74 Ast.StatementTag(_) | Ast.StmtDotsTag(_)
75 | Ast.DeclarationTag(_) | Ast.DeclDotsTag(_) -> true | _ -> false))
76
77 let modif_before x =
78 match Ast0.get_mcodekind x with
79 Ast0.PLUS _ -> failwith "not possible"
80 | Ast0.MINUS mc ->
81 (match !mc with
82 (* do better for the common case of replacing a stmt by another one *)
83 ([[Ast.StatementTag(s)]],ti) ->
84 (match Ast.unwrap s with
85 Ast.IfThen(_,_,_) -> true (* potentially dangerous *)
86 | _ -> mc := ([[Ast.StatementTag(s)]],ti); false)
87 | (_,_) -> true)
88 | Ast0.CONTEXT mc | Ast0.MIXED mc ->
89 (match !mc with
90 (Ast.BEFORE _,_,_) -> true
91 | (Ast.BEFOREAFTER _,_,_) -> true
92 | _ -> false)
93
94 let modif_after x =
95 match Ast0.get_mcodekind x with
96 Ast0.PLUS _ -> failwith "not possible"
97 | Ast0.MINUS mc ->
98 (match !mc with
99 (* do better for the common case of replacing a stmt by another one *)
100 ([[Ast.StatementTag(s)]],ti) ->
101 (match Ast.unwrap s with
102 Ast.IfThen(_,_,_) -> true (* potentially dangerous *)
103 | _ -> mc := ([[Ast.StatementTag(s)]],ti); false)
104 | (l,_) when any_statements l -> true
105 | (l,ti) -> mc := (l,ti); false)
106 | Ast0.CONTEXT mc | Ast0.MIXED mc ->
107 (match !mc with
108 (Ast.AFTER _,_,_) -> true
109 | (Ast.BEFOREAFTER _,_,_) -> true
110 | _ -> false)
111
112 (* Identifier *)
113 let rec left_ident i =
114 modif_before i or
115 match Ast0.unwrap i with
116 Ast0.Id(name) -> modif_before_mcode name
117 | Ast0.MetaId(name,_,_) -> modif_before_mcode name
118 | Ast0.MetaFunc(name,_,_) -> modif_before_mcode name
119 | Ast0.MetaLocalFunc(name,_,_) -> modif_before_mcode name
120 | Ast0.OptIdent(id) -> left_ident id
121 | Ast0.UniqueIdent(id) -> left_ident id
122
123 (* --------------------------------------------------------------------- *)
124 (* Expression *)
125
126 let rec left_expression e =
127 modif_before e or
128 match Ast0.unwrap e with
129 Ast0.Ident(id) -> left_ident id
130 | Ast0.Constant(const) -> modif_before_mcode const
131 | Ast0.FunCall(fn,lp,args,rp) -> left_expression fn
132 | Ast0.Assignment(left,op,right,_) -> left_expression left
133 | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> left_expression exp1
134 | Ast0.Postfix(exp,op) -> left_expression exp
135 | Ast0.Infix(exp,op) -> modif_before_mcode op
136 | Ast0.Unary(exp,op) -> modif_before_mcode op
137 | Ast0.Binary(left,op,right) -> left_expression left
138 | Ast0.Nested(left,op,right) -> left_expression left
139 | Ast0.Paren(lp,exp,rp) -> modif_before_mcode lp
140 | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> left_expression exp1
141 | Ast0.RecordAccess(exp,pt,field) -> left_expression exp
142 | Ast0.RecordPtAccess(exp,ar,field) -> left_expression exp
143 | Ast0.Cast(lp,ty,rp,exp) -> modif_before_mcode lp
144 | Ast0.SizeOfExpr(szf,exp) -> modif_before_mcode szf
145 | Ast0.SizeOfType(szf,lp,ty,rp) -> modif_before_mcode szf
146 | Ast0.TypeExp(ty) -> left_typeC ty
147 | Ast0.MetaErr(name,_,_) -> modif_before_mcode name
148 | Ast0.MetaExpr(name,_,ty,_,_) -> modif_before_mcode name
149 | Ast0.MetaExprList(name,_,_) -> modif_before_mcode name
150 | Ast0.EComma(cm) -> modif_before_mcode cm
151 | Ast0.DisjExpr(_,exp_list,_,_) -> List.exists left_expression exp_list
152 | Ast0.NestExpr(starter,expr_dots,ender,_,multi) ->
153 left_dots left_expression expr_dots
154 | Ast0.Edots(dots,_) | Ast0.Ecircles(dots,_) | Ast0.Estars(dots,_) -> false
155 | Ast0.OptExp(exp) -> left_expression exp
156 | Ast0.UniqueExp(exp) -> left_expression exp
157
158 (* --------------------------------------------------------------------- *)
159 (* Types *)
160
161 and left_typeC t =
162 modif_before t or
163 match Ast0.unwrap t with
164 Ast0.ConstVol(cv,ty) -> modif_before_mcode cv
165 | Ast0.BaseType(ty,strings) -> modif_before_mcode (List.hd strings)
166 | Ast0.Signed(sgn,ty) -> modif_before_mcode sgn
167 | Ast0.Pointer(ty,star) -> left_typeC ty
168 | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> left_typeC ty
169 | Ast0.FunctionType(Some ty,lp1,params,rp1) -> left_typeC ty
170 | Ast0.FunctionType(None,lp1,params,rp1) -> modif_before_mcode lp1
171 | Ast0.Array(ty,lb,size,rb) -> left_typeC ty
172 | Ast0.EnumName(kind,name) -> modif_before_mcode kind
173 | Ast0.StructUnionName(kind,name) -> modif_before_mcode kind
174 | Ast0.StructUnionDef(ty,lb,decls,rb) -> left_typeC ty
175 | Ast0.TypeName(name) -> modif_before_mcode name
176 | Ast0.MetaType(name,_) -> modif_before_mcode name
177 | Ast0.DisjType(lp,types,mids,rp) -> List.exists left_typeC types
178 | Ast0.OptType(ty) -> left_typeC ty
179 | Ast0.UniqueType(ty) -> left_typeC ty
180
181 (* --------------------------------------------------------------------- *)
182 (* Variable declaration *)
183 (* Even if the Cocci program specifies a list of declarations, they are
184 split out into multiple declarations of a single variable each. *)
185
186 and left_declaration d =
187 modif_before d or
188 match Ast0.unwrap d with
189 Ast0.Init(Some stg,ty,id,eq,ini,sem) -> modif_before_mcode stg
190 | Ast0.Init(None,ty,id,eq,ini,sem) -> left_typeC ty
191 | Ast0.UnInit(Some stg,ty,id,sem) -> modif_before_mcode stg
192 | Ast0.UnInit(None,ty,id,sem) -> left_typeC ty
193 | Ast0.MacroDecl(name,lp,args,rp,sem) -> left_ident name
194 | Ast0.TyDecl(ty,sem) -> left_typeC ty
195 | Ast0.Typedef(stg,ty,id,sem) -> modif_before_mcode stg
196 | Ast0.DisjDecl(_,decls,_,_) -> List.exists left_declaration decls
197 | Ast0.Ddots(dots,_) -> false
198 | Ast0.OptDecl(decl) -> left_declaration decl
199 | Ast0.UniqueDecl(decl) -> left_declaration decl
200
201 and right_declaration d =
202 modif_before d or
203 match Ast0.unwrap d with
204 Ast0.Init(_,ty,id,eq,ini,sem) -> modif_after_mcode sem
205 | Ast0.UnInit(_,ty,id,sem) -> modif_after_mcode sem
206 | Ast0.MacroDecl(name,lp,args,rp,sem) -> modif_after_mcode sem
207 | Ast0.TyDecl(ty,sem) -> modif_after_mcode sem
208 | Ast0.Typedef(stg,ty,id,sem) -> modif_after_mcode sem
209 | Ast0.DisjDecl(_,decls,_,_) -> List.exists right_declaration decls
210 | Ast0.Ddots(dots,_) -> false
211 | Ast0.OptDecl(decl) -> right_declaration decl
212 | Ast0.UniqueDecl(decl) -> right_declaration decl
213
214 (* --------------------------------------------------------------------- *)
215 (* Top-level code *)
216
217 and left_statement s =
218 modif_before s or
219 match Ast0.unwrap s with
220 Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) ->
221 (* irrelevant *) false
222 | Ast0.Decl(_,decl) -> left_declaration decl
223 | Ast0.Seq(lbrace,body,rbrace) -> modif_before_mcode lbrace
224 | Ast0.ExprStatement(exp,sem) -> left_expression exp
225 | Ast0.IfThen(iff,lp,exp,rp,branch1,(info,aft)) -> modif_before_mcode iff
226 | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,(info,aft)) ->
227 modif_before_mcode iff
228 | Ast0.While(whl,lp,exp,rp,body,(info,aft)) -> modif_before_mcode whl
229 | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> modif_before_mcode d
230 | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,(info,aft)) ->
231 modif_before_mcode fr
232 | Ast0.Iterator(nm,lp,args,rp,body,(info,aft)) -> left_ident nm
233 | Ast0.Switch(switch,lp,exp,rp,lb,decls,cases,rb) ->
234 modif_before_mcode switch
235 | Ast0.Break(br,sem) -> modif_before_mcode br
236 | Ast0.Continue(cont,sem) -> modif_before_mcode cont
237 | Ast0.Label(l,dd) -> left_ident l
238 | Ast0.Goto(goto,l,sem) -> modif_before_mcode goto
239 | Ast0.Return(ret,sem) -> modif_before_mcode ret
240 | Ast0.ReturnExpr(ret,exp,sem) -> modif_before_mcode ret
241 | Ast0.MetaStmt(name,pure) -> modif_before_mcode name
242 | Ast0.MetaStmtList(name,_) -> modif_before_mcode name
243 | Ast0.Disj(_,statement_dots_list,_,_) ->
244 List.exists (left_dots left_statement) statement_dots_list
245 | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) ->
246 left_dots left_statement stmt_dots
247 | Ast0.Exp(exp) -> false (* can only be replaced by an expression *)
248 | Ast0.TopExp(exp) -> false (* as above *)
249 | Ast0.Ty(ty) -> false (* can only be replaced by a type *)
250 | Ast0.TopInit(init) -> false (* can only be replaced by an init *)
251 | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> false
252 | Ast0.Include(inc,s) -> modif_before_mcode inc
253 | Ast0.Define(def,id,params,body) -> modif_before_mcode def
254 | Ast0.OptStm(re) -> left_statement re
255 | Ast0.UniqueStm(re) -> left_statement re
256
257 and right_statement s =
258 modif_after s or
259 match Ast0.unwrap s with
260 Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) ->
261 (* irrelevant *) false
262 | Ast0.Decl(_,decl) -> right_declaration decl
263 | Ast0.Seq(lbrace,body,rbrace) -> modif_after_mcode rbrace
264 | Ast0.ExprStatement(exp,sem) -> modif_after_mcode sem
265 | Ast0.IfThen(iff,lp,exp,rp,branch1,(info,aft)) -> modif_after_mcodekind aft
266 | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,(info,aft)) ->
267 modif_after_mcodekind aft
268 | Ast0.While(whl,lp,exp,rp,body,(info,aft)) -> modif_after_mcodekind aft
269 | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> modif_after_mcode sem
270 | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,(info,aft)) ->
271 modif_after_mcodekind aft
272 | Ast0.Iterator(nm,lp,args,rp,body,(info,aft)) ->
273 modif_after_mcodekind aft
274 | Ast0.Switch(switch,lp,exp,rp,lb,decls,cases,rb) -> modif_after_mcode rb
275 | Ast0.Break(br,sem) -> modif_after_mcode sem
276 | Ast0.Continue(cont,sem) -> modif_after_mcode sem
277 | Ast0.Label(l,dd) -> modif_after_mcode dd
278 | Ast0.Goto(goto,l,sem) -> modif_after_mcode sem
279 | Ast0.Return(ret,sem) -> modif_after_mcode sem
280 | Ast0.ReturnExpr(ret,exp,sem) -> modif_after_mcode sem
281 | Ast0.MetaStmt(name,pure) -> modif_after_mcode name
282 | Ast0.MetaStmtList(name,_) -> modif_after_mcode name
283 | Ast0.Disj(_,statement_dots_list,_,_) ->
284 List.exists (right_dots right_statement) statement_dots_list
285 | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) ->
286 right_dots right_statement stmt_dots
287 | Ast0.Exp(exp) -> false (* can only be replaced by an expression *)
288 | Ast0.TopExp(exp) -> false (* as above *)
289 | Ast0.Ty(ty) -> false (* can only be replaced by a type *)
290 | Ast0.TopInit(init) -> false (* can only be replaced by an init *)
291 | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> false
292 | Ast0.Include(inc,s) -> modif_after_mcode s
293 | Ast0.Define(def,id,params,body) -> right_dots right_statement body
294 | Ast0.OptStm(re) -> right_statement re
295 | Ast0.UniqueStm(re) -> right_statement re
296
297 (* --------------------------------------------------------------------- *)
298
299
300 (* A very coarse approximation. We would really only like to return true
301 if a new statement is added. For this it would be best to correlate with the
302 plus slice. Or at least be sure that the new stuff is on the far left or
303 far right. *)
304
305 let rec adding_something s =
306 match Ast0.get_mcodekind s with
307 Ast0.MINUS(mc) ->
308 (match !mc with
309 (* do better for the common case of replacing a stmt by another one *)
310 ([[Ast.StatementTag(s)]],ti) ->
311 (match Ast.unwrap s with
312 Ast.IfThen(_,_,_) -> true (* potentially dangerous *)
313 | _ -> mc := ([[Ast.StatementTag(s)]],ti); false)
314 | (_,_) -> true)
315 | Ast0.CONTEXT(mc) ->
316 let (text,tinfo1,tinfo2) = !mc in
317 (match text with Ast.NOTHING -> false | _ -> true)
318 | Ast0.MIXED(_) ->
319 not(contains_only_minus.VT0.combiner_rec_statement s) (*&&
320 (left_statement s) or (right_statement s)*)
321 | _ -> failwith "unexpected plus code"
322
323 (* why do we need this; MINUS should mean the same thing *)
324 and contains_only_minus =
325 let bind x y = x && y in
326 let option_default = true in
327 let mcodekind = function
328 Ast0.MINUS(mc) ->
329 (match !mc with
330 ([],_) -> true
331 | _ -> false)
332 | Ast0.CONTEXT(mc) -> false
333 | _ -> false in
334 let mcode (_,_,_,mc,_,_) = mcodekind mc in
335
336 let donothing r k e = mcodekind (Ast0.get_mcodekind e) && k e in
337
338 let dots r k e =
339 match Ast0.unwrap e with
340 Ast0.DOTS([]) | Ast0.CIRCLES([]) | Ast0.STARS([]) -> true
341 | _ -> k e in
342
343 let expression r k e =
344 mcodekind (Ast0.get_mcodekind e) &&
345 match Ast0.unwrap e with
346 Ast0.DisjExpr(starter,expr_list,mids,ender) ->
347 List.for_all r.VT0.combiner_rec_expression expr_list
348 | _ -> k e in
349
350 let declaration r k e =
351 mcodekind (Ast0.get_mcodekind e) &&
352 match Ast0.unwrap e with
353 Ast0.DisjDecl(starter,decls,mids,ender) ->
354 List.for_all r.VT0.combiner_rec_declaration decls
355 | _ -> k e in
356
357 let typeC r k e =
358 mcodekind (Ast0.get_mcodekind e) &&
359 match Ast0.unwrap e with
360 Ast0.DisjType(starter,types,mids,ender) ->
361 List.for_all r.VT0.combiner_rec_typeC types
362 | _ -> k e in
363
364 let statement r k e =
365 mcodekind (Ast0.get_mcodekind e) &&
366 match Ast0.unwrap e with
367 Ast0.Disj(starter,statement_dots_list,mids,ender) ->
368 List.for_all r.VT0.combiner_rec_statement_dots statement_dots_list
369 | _ -> k e in
370
371 let case_line r k e =
372 mcodekind (Ast0.get_mcodekind e) &&
373 match Ast0.unwrap e with
374 Ast0.DisjCase(starter,case_list,mids,ender) ->
375 List.for_all r.VT0.combiner_rec_case_line case_list
376 | _ -> k e in
377
378 V0.flat_combiner bind option_default
379 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
380 dots dots dots dots dots dots
381 donothing expression typeC donothing donothing declaration
382 statement case_line donothing
383
384
385 (* needs a special case when there is a Disj or an empty DOTS *)
386 (* ---------------------------------------------------------------------- *)
387
388 (*
389 Doesn't really work:
390
391 if (acpi_device_dir(device))
392 + {
393 remove_proc_entry(acpi_device_bid(device), acpi_ac_dir);
394 + acpi_device_dir(device) = NULL;
395 + }
396
397 The last two + lines get associated with the end of the if, not with the
398 branch, so the braces get added in oddly.
399 *)
400
401 let add_braces orig_s =
402 let s =
403 (Iso_pattern.rebuild_mcode None).VT0.rebuilder_rec_statement orig_s in
404 let new_mcodekind =
405 match Ast0.get_mcodekind s with
406 Ast0.MINUS(mc) ->
407 let (text,tinfo) = !mc in
408 Ast0.MINUS(ref([Ast.mkToken "{"]::text@[[Ast.mkToken "}"]],tinfo))
409 | Ast0.CONTEXT(mc) ->
410 let (text,tinfo1,tinfo2) = !mc in
411 let new_text =
412 (* this is going to be a mess if we allow it to be iterable...
413 there would be one level of braces for every added things.
414 need to come up with something better, or just add {} in the
415 source code. *)
416 match text with
417 Ast.BEFORE(bef,_) ->
418 Ast.BEFOREAFTER([Ast.mkToken "{"]::bef,[[Ast.mkToken "}"]],
419 Ast.ONE)
420 | Ast.AFTER(aft,_) ->
421 Ast.BEFOREAFTER([[Ast.mkToken "{"]],aft@[[Ast.mkToken "}"]],
422 Ast.ONE)
423 | Ast.BEFOREAFTER(bef,aft,_) ->
424 Ast.BEFOREAFTER([Ast.mkToken "{"]::bef,aft@[[Ast.mkToken "}"]],
425 Ast.ONE)
426 | Ast.NOTHING ->
427 Ast.BEFOREAFTER([[Ast.mkToken "{"]],[[Ast.mkToken "}"]],
428 Ast.ONE) in
429 Ast0.CONTEXT(ref(new_text,tinfo1,tinfo2))
430 | Ast0.MIXED(mc) ->
431 let (text,tinfo1,tinfo2) = !mc in
432 let new_text =
433 match text with
434 Ast.BEFORE(bef,_) ->
435 Ast.BEFOREAFTER([Ast.mkToken "{"]::bef,[[Ast.mkToken "}"]],
436 Ast.ONE)
437 | Ast.AFTER(aft,_) ->
438 Ast.BEFOREAFTER([[Ast.mkToken "{"]],aft@[[Ast.mkToken "}"]],
439 Ast.ONE)
440 | Ast.BEFOREAFTER(bef,aft,_) ->
441 Ast.BEFOREAFTER([Ast.mkToken "{"]::bef,aft@[[Ast.mkToken "}"]],
442 Ast.ONE)
443 | Ast.NOTHING ->
444 Ast.BEFOREAFTER([[Ast.mkToken "{"]],[[Ast.mkToken "}"]],
445 Ast.ONE) in
446 Ast0.MIXED(ref(new_text,tinfo1,tinfo2))
447 | _ -> failwith "unexpected plus code" in
448 Ast0.set_mcodekind s new_mcodekind;
449 Compute_lines.compute_statement_lines true s
450
451 (* ---------------------------------------------------------------------- *)
452
453 let is_dots x =
454 match Ast0.unwrap x with
455 Ast0.Dots(_,_) | Ast0.Circles(_,_) | Ast0.Stars(_,_)
456 | Ast0.Nest(_,_,_,_,_) -> true
457 | _ -> false
458
459 let all_minus s =
460 match Ast0.get_mcodekind s with
461 Ast0.MINUS(_) -> true
462 | _ -> false
463
464 let rec unchanged_minus s =
465 match Ast0.get_mcodekind s with
466 Ast0.MINUS(mc) -> (match !mc with ([],_) -> true | _ -> false)
467 | _ -> false
468
469 let rec do_branch s =
470 if unchanged_minus s
471 then
472 Ast0.set_dots_bef_aft s (Ast0.DroppingBetweenDots(add_braces s))
473 else
474 match Ast0.unwrap s with
475 Ast0.Disj(starter,statement_dots_list,mids,ender) ->
476 let stmts =
477 List.map
478 (function s ->
479 match Ast0.unwrap s with
480 Ast0.DOTS([s]) ->
481 Ast0.rewrap s (Ast0.DOTS([do_branch s]))
482 | Ast0.DOTS(_) -> s
483 | _ -> failwith "not supported")
484 statement_dots_list in
485 Ast0.rewrap s (Ast0.Disj(starter,stmts,mids,ender))
486 | _ -> s
487
488 let rec statement dots_before dots_after s =
489 let do_one s =
490 if dots_before && dots_after
491 then
492 if unchanged_minus s
493 then
494 (let with_braces = add_braces s in
495 Ast0.set_dots_bef_aft s (Ast0.DroppingBetweenDots(with_braces)))
496 else if adding_something s
497 then
498 (let with_braces = add_braces s in
499 Ast0.set_dots_bef_aft s (Ast0.AddingBetweenDots(with_braces)))
500 else s
501 else s in
502
503 match Ast0.unwrap s with
504 Ast0.FunDecl(x,fninfo,name,lp,params,rp,lbrace,body,rbrace) ->
505 (* true for close brace, because that represents any way we can
506 exit the function, which is not necessarily followed by an explicit
507 close brace. *)
508 Ast0.rewrap s
509 (Ast0.FunDecl(x,fninfo,name,lp,params,rp,lbrace,
510 statement_dots false true body,
511 rbrace))
512 | Ast0.Decl(_,_) -> s
513 | Ast0.Seq(lbrace,body,rbrace) ->
514 Ast0.rewrap s
515 (Ast0.Seq(lbrace,statement_dots false false body,rbrace))
516 | Ast0.ExprStatement(exp,sem) -> do_one s
517 | Ast0.IfThen(iff,lp,exp,rp,branch1,x) ->
518 do_one
519 (Ast0.rewrap s
520 (Ast0.IfThen(iff,lp,exp,rp,statement false false branch1,x)))
521 | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,x) ->
522 do_one
523 (Ast0.rewrap s
524 (Ast0.IfThenElse
525 (iff,lp,exp,rp,
526 statement false false branch1,els,
527 statement false false branch2,x)))
528 | Ast0.While(whl,lp,exp,rp,body,x) ->
529 do_one
530 (Ast0.rewrap s
531 (Ast0.While(whl,lp,exp,rp,statement false false body,x)))
532 | Ast0.Do(d,body,whl,lp,exp,rp,sem) ->
533 do_one
534 (Ast0.rewrap s
535 (Ast0.Do(d,statement false false body,whl,lp,exp,rp,sem)))
536 | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,x) ->
537 do_one
538 (Ast0.rewrap s
539 (Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,
540 statement false false body,x)))
541 | Ast0.Iterator(nm,lp,args,rp,body,x) ->
542 do_one
543 (Ast0.rewrap s
544 (Ast0.Iterator(nm,lp,args,rp,statement false false body,x)))
545 | Ast0.Switch(switch,lp,exp,rp,lb,decls,cases,rb) ->
546 do_one
547 (Ast0.rewrap s
548 (Ast0.Switch(switch,lp,exp,rp,lb,decls,
549 Ast0.rewrap cases
550 (Ast0.DOTS
551 (List.map case_line (Ast0.undots cases))),
552 rb)))
553 | Ast0.Break(br,sem) -> do_one s
554 | Ast0.Continue(cont,sem) -> do_one s
555 | Ast0.Label(l,dd) -> do_one s
556 | Ast0.Goto(goto,l,sem) -> do_one s
557 | Ast0.Return(ret,sem) -> do_one s
558 | Ast0.ReturnExpr(ret,exp,sem) -> do_one s
559 | Ast0.MetaStmt(name,_) -> do_one s
560 | Ast0.MetaStmtList(name,_) -> do_one s
561 | Ast0.Disj(starter,statement_dots_list,mids,ender) ->
562 Ast0.rewrap s
563 (Ast0.Disj(starter,
564 List.map (statement_dots dots_before dots_after)
565 statement_dots_list,
566 mids,ender))
567 | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) ->
568 (match Ast0.get_mcode_mcodekind starter with
569 Ast0.MINUS _ -> (* everything removed, like -... *) s
570 | _ ->
571 Ast0.rewrap s
572 (Ast0.Nest
573 (starter,statement_dots true true stmt_dots,ender,
574 whencode,multi)))
575 | Ast0.Exp(exp) -> s
576 | Ast0.TopExp(exp) -> s
577 | Ast0.Ty(ty) -> s
578 | Ast0.TopInit(init) -> s
579 | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> s
580 | Ast0.Include(inc,string) -> s (* doesn't affect the need for braces *)
581 | Ast0.Define(def,id,params,body) -> s (* same as include *)
582 | Ast0.OptStm(re) ->
583 Ast0.rewrap s
584 (Ast0.OptStm(statement dots_before dots_after re))
585 | Ast0.UniqueStm(re) ->
586 Ast0.rewrap s
587 (Ast0.UniqueStm(statement dots_before dots_after re))
588
589 and case_line c =
590 Ast0.rewrap c
591 (match Ast0.unwrap c with
592 Ast0.Default(def,colon,code) ->
593 Ast0.Default(def,colon,statement_dots false false code)
594 | Ast0.Case(case,exp,colon,code) ->
595 Ast0.Case(case,exp,colon,statement_dots false false code)
596 | Ast0.DisjCase(starter,case_lines,mids,ender) ->
597 Ast0.DisjCase(starter,List.map case_line case_lines,mids,ender)
598 | Ast0.OptCase(case) -> Ast0.OptCase(case_line c))
599
600 and do_statement_dots dots_before dots_after = function
601 [] -> []
602 | [x] -> [statement dots_before dots_after x]
603 | dots::rest when is_dots dots ->
604 dots::(do_statement_dots true dots_after rest)
605 | x::(dots::_ as rest) when is_dots dots ->
606 (statement dots_before true x)::
607 do_statement_dots false dots_after rest
608 | x::rest ->
609 (statement dots_before false x)::
610 do_statement_dots false dots_after rest
611
612 and statement_dots dots_before dots_after d =
613 Ast0.rewrap d
614 (match Ast0.unwrap d with
615 Ast0.DOTS(l) ->
616 Ast0.DOTS(do_statement_dots dots_before dots_after l)
617 | Ast0.CIRCLES(l) ->
618 Ast0.CIRCLES(do_statement_dots dots_before dots_after l)
619 | Ast0.STARS(l) ->
620 Ast0.STARS(do_statement_dots dots_before dots_after l))
621
622 let top_level t =
623 Ast0.rewrap t
624 (match Ast0.unwrap t with
625 Ast0.DECL(stmt_dots) -> Ast0.DECL(statement true true stmt_dots)
626 | Ast0.CODE(stmt_dots) -> Ast0.CODE(statement_dots true true stmt_dots)
627 | t -> t)
628
629 let single_statement l =
630 if !Flag_parsing_cocci.sgrep_mode then l else List.map top_level l