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