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