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