Release coccinelle-0.2.4
[bpt/coccinelle.git] / engine / asttomember.ml
CommitLineData
9bc82bae
C
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
c491d8ee
C
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
34e49164
C
49(* on the first pass, onlyModif is true, so we don't see all matched nodes,
50only modified ones *)
51
52module Ast = Ast_cocci
53module V = Visitor_ast
54module CTL = Ast_ctl
55
56let mcode r (_,_,kind,_) =
57 match kind with
708f4980 58 Ast.MINUS(_,_,_,_) -> true
951c7801 59 | Ast.PLUS _ -> failwith "not possible"
34e49164
C
60 | Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING)
61
62let no_mcode _ _ = false
63
64let contains_modif used_after x =
65 if List.exists (function x -> List.mem x used_after) (Ast.get_fvs x)
66 then true
67 else
68 let bind x y = x or y in
69 let option_default = false in
70 let do_nothing r k e = k e in
71 let rule_elem r k re =
72 let res = k re in
73 match Ast.unwrap re with
74 Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) ->
75 bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
76 | Ast.Decl(bef,_,decl) ->
77 bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
78 | _ -> res in
79 let recursor =
80 V.combiner bind option_default
81 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
faf9a90c 82 mcode
c491d8ee 83 do_nothing do_nothing do_nothing do_nothing do_nothing
34e49164
C
84 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
85 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
86 recursor.V.combiner_rule_elem x
87
88(* contains an inherited metavariable or contains a constant *)
89let contains_constant x =
90 match Ast.get_inherited x with
91 [] ->
92 let bind x y = x or y in
93 let option_default = false in
94 let do_nothing r k e = k e in
95 let mcode _ _ = false in
96 let ident r k i =
97 match Ast.unwrap i with
98 Ast.Id(name) -> true
99 | _ -> k i in
100 let expr r k e =
101 match Ast.unwrap e with
102 Ast.Constant(const) -> true
103 | _ -> k e in
104 let recursor =
105 V.combiner bind option_default
106 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
faf9a90c 107 mcode
c491d8ee 108 do_nothing do_nothing do_nothing do_nothing do_nothing
34e49164
C
109 ident expr do_nothing do_nothing do_nothing do_nothing
110 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing in
111 recursor.V.combiner_rule_elem x
112 | _ -> true
113
114(* --------------------------------------------------------------------- *)
115
116let print_info = function
117 [] -> Printf.printf "no information\n"
118 | l ->
119 List.iter
120 (function disj ->
121 Printf.printf "one set of required things %d:\n"
122 (List.length disj);
123 List.iter
124 (function (_,thing) ->
125 Printf.printf "%s\n"
126 (Pretty_print_cocci.rule_elem_to_string thing))
127 disj;)
128 l
129
130(* --------------------------------------------------------------------- *)
131
132(* drop all distinguishing information from a term *)
133let strip =
134 let do_nothing r k e = Ast.make_term (Ast.unwrap (k e)) in
135 let do_absolutely_nothing r k e = k e in
136 let mcode m = Ast.make_mcode(Ast.unwrap_mcode m) in
137 let rule_elem r k re =
138 let res = do_nothing r k re in
139 let no_mcode = Ast.CONTEXT(Ast.NoPos,Ast.NOTHING) in
140 match Ast.unwrap res with
141 Ast.FunHeader(bef,b,fninfo,name,lp,params,rp) ->
142 Ast.rewrap res
143 (Ast.FunHeader(no_mcode,b,fninfo,name,lp,params,rp))
144 | Ast.Decl(bef,b,decl) -> Ast.rewrap res (Ast.Decl(no_mcode,b,decl))
145 | _ -> res in
146 let recursor =
147 V.rebuilder
148 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
c491d8ee 149 do_nothing do_nothing do_nothing do_nothing do_nothing
34e49164
C
150 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
151 do_nothing rule_elem do_nothing do_nothing
152 do_nothing do_absolutely_nothing in
153 recursor.V.rebuilder_rule_elem
154
155(* --------------------------------------------------------------------- *)
156
157let disj l1 l2 = l1 l2
158
159let rec conj xs ys =
160 match (xs,ys) with
161 ([],_) -> ys
162 | (_,[]) -> xs
163 | _ ->
164 List.fold_left
165 (function prev ->
166 function x ->
167 List.fold_left
168 (function prev ->
169 function cur ->
170 let cur_res = (List.sort compare (Common.union_set x cur)) in
171 cur_res ::
172 (List.filter
173 (function x -> not (Common.include_set cur_res x))
174 prev))
175 prev ys)
176 [] xs
177
178let conj_wrapped x l = conj [List.map (function x -> (1,strip x)) x] l
179
180(* --------------------------------------------------------------------- *)
181(* the main translation loop *)
182
183let rule_elem re =
184 match Ast.unwrap re with
185 Ast.DisjRuleElem(res) -> [[(List.length res,strip re)]]
186 | _ -> [[(1,strip re)]]
187
188let conj_one testfn x l =
189 if testfn x
190 then conj (rule_elem x) l
191 else l
192
193let rec statement_list testfn mcode tail stmt_list : 'a list list =
194 match Ast.unwrap stmt_list with
195 Ast.DOTS(x) | Ast.CIRCLES(x) | Ast.STARS(x) ->
196 (match List.rev x with
197 [] -> []
198 | last::rest ->
199 List.fold_right
200 (function cur ->
201 function rest ->
202 conj (statement testfn mcode false cur) rest)
203 rest (statement testfn mcode tail last))
204
205and statement testfn mcode tail stmt : 'a list list =
206 match Ast.unwrap stmt with
207 Ast.Atomic(ast) ->
208 (match Ast.unwrap ast with
209 (* modifications on return are managed in some other way *)
210 Ast.Return(_,_) | Ast.ReturnExpr(_,_,_) when tail -> []
211 | _ -> if testfn ast then rule_elem ast else [])
708f4980
C
212 | Ast.Seq(lbrace,body,rbrace) ->
213 let body_info = statement_list testfn mcode tail body in
34e49164
C
214 if testfn lbrace or testfn rbrace
215 then conj_wrapped [lbrace;rbrace] body_info
216 else body_info
217
218 | Ast.IfThen(header,branch,(_,_,_,aft))
219 | Ast.While(header,branch,(_,_,_,aft))
220 | Ast.For(header,branch,(_,_,_,aft))
221 | Ast.Iterator(header,branch,(_,_,_,aft)) ->
222 if testfn header or mcode () ((),(),aft,Ast.NoMetaPos)
223 then conj (rule_elem header) (statement testfn mcode tail branch)
224 else statement testfn mcode tail branch
225
fc1ad971
C
226 | Ast.Switch(header,lb,decls,cases,rb) ->
227 let body_info =
228 conj
229 (statement_list testfn mcode false decls)
230 (case_lines testfn mcode tail cases) in
34e49164
C
231 if testfn header or testfn lb or testfn rb
232 then conj (rule_elem header) body_info
233 else body_info
234
235 | Ast.IfThenElse(ifheader,branch1,els,branch2,(_,_,_,aft)) ->
236 let branches =
237 conj
238 (statement testfn mcode tail branch1)
239 (statement testfn mcode tail branch2) in
240 if testfn ifheader or mcode () ((),(),aft,Ast.NoMetaPos)
241 then conj (rule_elem ifheader) branches
242 else branches
243
244 | Ast.Disj(stmt_dots_list) ->
245 let processed =
246 List.map (statement_list testfn mcode tail) stmt_dots_list in
247 (* if one branch gives no information, then we have to take anything *)
248 if List.exists (function [] -> true | _ -> false) processed
249 then []
250 else Common.union_all processed
251
5636bb2c 252 | Ast.Nest(starter,stmt_dots,ender,whencode,true,_,_) ->
34e49164
C
253 statement_list testfn mcode false stmt_dots
254
5636bb2c 255 | Ast.Nest(starter,stmt_dots,ender,whencode,false,_,_) -> []
34e49164
C
256
257 | Ast.Dots(_,whencodes,_,_) -> []
258
708f4980
C
259 | Ast.FunDecl(header,lbrace,body,rbrace) ->
260 let body_info = statement_list testfn mcode true body in
34e49164
C
261 if testfn header or testfn lbrace or testfn rbrace
262 then conj (rule_elem header) body_info
263 else body_info
264
265 | Ast.Define(header,body) ->
266 conj_one testfn header (statement_list testfn mcode tail body)
267
268 | Ast.OptStm(stm) -> []
269
270 | Ast.UniqueStm(stm) -> statement testfn mcode tail stm
271
272 | _ -> failwith "not supported"
273
274and case_lines testfn mcode tail cases =
275 match cases with
276 [] -> []
277 | last::rest ->
278 List.fold_right
279 (function cur ->
280 function rest ->
281 conj (case_line testfn mcode false cur) rest)
282 rest (case_line testfn mcode tail last)
283
284and case_line testfn mcode tail case =
285 match Ast.unwrap case with
286 Ast.CaseLine(header,code) ->
287 conj_one testfn header (statement_list testfn mcode tail code)
ae4735db 288
34e49164
C
289 | Ast.OptCase(case) -> []
290
291(* --------------------------------------------------------------------- *)
292(* Function declaration *)
293
294let top_level testfn mcode t : 'a list list =
295 match Ast.unwrap t with
296 Ast.FILEINFO(old_file,new_file) -> failwith "not supported fileinfo"
297 | Ast.DECL(stmt) -> statement testfn mcode false stmt
298 | Ast.CODE(stmt_dots) -> statement_list testfn mcode false stmt_dots
299 | Ast.ERRORWORDS(exps) -> failwith "not supported errorwords"
300
301(* --------------------------------------------------------------------- *)
302(* Entry points *)
303
304let debug = false
305
306(* if we end up with nothing, we assume that this rule is only here because
307someone depends on it, and thus we try again with testfn as contains_modif.
308Alternatively, we could check that this rule is mentioned in some
309dependency, but that would be a little more work, and doesn't seem
310worthwhile. *)
311
312(* lists are sorted such that smaller DisjRuleElem are first, because they
313are cheaper to test *)
314
315let asttomemberz (_,_,l) used_after =
316 let process_one (l : (int * Ast_cocci.rule_elem) list list) =
317 if debug
318 then print_info l;
319 List.map
320 (function info ->
321 let info =
322 List.sort (function (n1,_) -> function (n2,_) -> compare n1 n2)
323 info in
324 List.map (function (_,x) -> (Lib_engine.Match(x),CTL.Control)) info)
325 l in
326 List.map2
327 (function min -> function (max,big_max) ->
328 match min with
329 [] ->
330 (match max() with
331 [] -> process_one (big_max())
332 | max -> process_one max)
333 | _ -> process_one min)
334 (List.map (top_level contains_constant no_mcode) l)
335 (List.combine
336 (List.map2
337 (function x -> function ua -> function _ ->
338 top_level (contains_modif ua) mcode x)
339 l used_after)
340 (List.map
341 (function x -> function _ ->
342 top_level (function _ -> true) no_mcode x)
343 l))
344
345let asttomember r used_after =
346 match r with
b1b2de81 347 Ast.ScriptRule _ | Ast.InitialScriptRule _ | Ast.FinalScriptRule _ -> []
faf9a90c 348 | Ast.CocciRule (a,b,c,_,_) -> asttomemberz (a,b,c) used_after
34e49164 349