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