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