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