2 * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen
3 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
4 * This file is part of Coccinelle.
6 * Coccinelle is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, according to version 2 of the License.
10 * Coccinelle is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
18 * The authors reserve the right to distribute this or future versions of
19 * Coccinelle under other licenses.
24 * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen
25 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
26 * This file is part of Coccinelle.
28 * Coccinelle is free software: you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation, according to version 2 of the License.
32 * Coccinelle is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
37 * You should have received a copy of the GNU General Public License
38 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
40 * The authors reserve the right to distribute this or future versions of
41 * Coccinelle under other licenses.
45 (* on the first pass, onlyModif is true, so we don't see all matched nodes,
48 module Ast
= Ast_cocci
49 module V
= Visitor_ast
52 let mcode r
(_
,_
,kind
,_
) =
54 Ast.MINUS
(_
,_
,_
,_
) -> true
55 | Ast.PLUS _
-> failwith
"not possible"
56 | Ast.CONTEXT
(_
,info
) -> not
(info
= Ast.NOTHING
)
58 let no_mcode _ _
= false
60 let contains_modif used_after x
=
61 if List.exists
(function x
-> List.mem x used_after
) (Ast.get_fvs x
)
64 let bind x y
= x
or y
in
65 let option_default = false in
66 let do_nothing r k e
= k e
in
67 let rule_elem r k re
=
69 match Ast.unwrap re
with
70 Ast.FunHeader
(bef
,_
,fninfo
,name
,lp
,params
,rp
) ->
71 bind (mcode r
((),(),bef
,Ast.NoMetaPos
)) res
72 | Ast.Decl
(bef
,_
,decl
) ->
73 bind (mcode r
((),(),bef
,Ast.NoMetaPos
)) res
76 V.combiner
bind option_default
77 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
79 do_nothing do_nothing do_nothing do_nothing
80 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
81 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
82 recursor.V.combiner_rule_elem x
84 (* contains an inherited metavariable or contains a constant *)
85 let contains_constant x
=
86 match Ast.get_inherited x
with
88 let bind x y
= x
or y
in
89 let option_default = false in
90 let do_nothing r k e
= k e
in
91 let mcode _ _
= false in
93 match Ast.unwrap i
with
97 match Ast.unwrap e
with
98 Ast.Constant
(const
) -> true
101 V.combiner
bind option_default
102 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
104 do_nothing do_nothing do_nothing do_nothing
105 ident expr do_nothing do_nothing do_nothing do_nothing
106 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing in
107 recursor.V.combiner_rule_elem x
110 (* --------------------------------------------------------------------- *)
112 let print_info = function
113 [] -> Printf.printf
"no information\n"
117 Printf.printf
"one set of required things %d:\n"
120 (function (_
,thing
) ->
122 (Pretty_print_cocci.rule_elem_to_string thing
))
126 (* --------------------------------------------------------------------- *)
128 (* drop all distinguishing information from a term *)
130 let do_nothing r k e
= Ast.make_term
(Ast.unwrap
(k e
)) in
131 let do_absolutely_nothing r k e
= k e
in
132 let mcode m
= Ast.make_mcode
(Ast.unwrap_mcode m
) in
133 let rule_elem r k re
=
134 let res = do_nothing r k re
in
135 let no_mcode = Ast.CONTEXT
(Ast.NoPos
,Ast.NOTHING
) in
136 match Ast.unwrap
res with
137 Ast.FunHeader
(bef
,b
,fninfo
,name
,lp
,params
,rp
) ->
139 (Ast.FunHeader
(no_mcode,b
,fninfo
,name
,lp
,params
,rp
))
140 | Ast.Decl
(bef
,b
,decl
) -> Ast.rewrap
res (Ast.Decl
(no_mcode,b
,decl
))
144 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
145 do_nothing do_nothing do_nothing do_nothing
146 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
147 do_nothing rule_elem do_nothing do_nothing
148 do_nothing do_absolutely_nothing in
149 recursor.V.rebuilder_rule_elem
151 (* --------------------------------------------------------------------- *)
153 let disj l1 l2
= l1 l2
166 let cur_res = (List.sort compare
(Common.union_set x cur
)) in
169 (function x
-> not
(Common.include_set
cur_res x
))
174 let conj_wrapped x l
= conj [List.map
(function x
-> (1,strip x
)) x
] l
176 (* --------------------------------------------------------------------- *)
177 (* the main translation loop *)
180 match Ast.unwrap re
with
181 Ast.DisjRuleElem
(res) -> [[(List.length
res,strip re
)]]
182 | _
-> [[(1,strip re
)]]
184 let conj_one testfn x l
=
186 then conj (rule_elem x
) l
189 let rec statement_list testfn
mcode tail stmt_list
: 'a list list
=
190 match Ast.unwrap stmt_list
with
191 Ast.DOTS
(x
) | Ast.CIRCLES
(x
) | Ast.STARS
(x
) ->
192 (match List.rev x
with
198 conj (statement testfn
mcode false cur
) rest
)
199 rest
(statement testfn
mcode tail last
))
201 and statement testfn
mcode tail stmt
: 'a list list
=
202 match Ast.unwrap stmt
with
204 (match Ast.unwrap ast
with
205 (* modifications on return are managed in some other way *)
206 Ast.Return
(_
,_
) | Ast.ReturnExpr
(_
,_
,_
) when tail
-> []
207 | _
-> if testfn ast
then rule_elem ast
else [])
208 | Ast.Seq
(lbrace
,body
,rbrace
) ->
209 let body_info = statement_list testfn
mcode tail body
in
210 if testfn lbrace
or testfn rbrace
211 then conj_wrapped [lbrace
;rbrace
] body_info
214 | Ast.IfThen
(header
,branch
,(_
,_
,_
,aft
))
215 | Ast.While
(header
,branch
,(_
,_
,_
,aft
))
216 | Ast.For
(header
,branch
,(_
,_
,_
,aft
))
217 | Ast.Iterator
(header
,branch
,(_
,_
,_
,aft
)) ->
218 if testfn header
or mcode () ((),(),aft
,Ast.NoMetaPos
)
219 then conj (rule_elem header
) (statement testfn
mcode tail branch
)
220 else statement testfn
mcode tail branch
222 | Ast.Switch
(header
,lb
,decls
,cases
,rb
) ->
225 (statement_list testfn
mcode false decls
)
226 (case_lines testfn
mcode tail cases
) in
227 if testfn header
or testfn lb
or testfn rb
228 then conj (rule_elem header
) body_info
231 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,(_
,_
,_
,aft
)) ->
234 (statement testfn
mcode tail branch1
)
235 (statement testfn
mcode tail branch2
) in
236 if testfn ifheader
or mcode () ((),(),aft
,Ast.NoMetaPos
)
237 then conj (rule_elem ifheader
) branches
240 | Ast.Disj
(stmt_dots_list
) ->
242 List.map
(statement_list testfn
mcode tail
) stmt_dots_list
in
243 (* if one branch gives no information, then we have to take anything *)
244 if List.exists
(function [] -> true | _
-> false) processed
246 else Common.union_all
processed
248 | Ast.Nest
(starter
,stmt_dots
,ender
,whencode
,true,_
,_
) ->
249 statement_list testfn
mcode false stmt_dots
251 | Ast.Nest
(starter
,stmt_dots
,ender
,whencode
,false,_
,_
) -> []
253 | Ast.Dots
(_
,whencodes
,_
,_
) -> []
255 | Ast.FunDecl
(header
,lbrace
,body
,rbrace
) ->
256 let body_info = statement_list testfn
mcode true body
in
257 if testfn header
or testfn lbrace
or testfn rbrace
258 then conj (rule_elem header
) body_info
261 | Ast.Define
(header
,body
) ->
262 conj_one testfn header
(statement_list testfn
mcode tail body
)
264 | Ast.OptStm
(stm
) -> []
266 | Ast.UniqueStm
(stm
) -> statement testfn
mcode tail stm
268 | _
-> failwith
"not supported"
270 and case_lines testfn
mcode tail cases
=
277 conj (case_line testfn
mcode false cur
) rest
)
278 rest
(case_line testfn
mcode tail last
)
280 and case_line testfn
mcode tail case
=
281 match Ast.unwrap case
with
282 Ast.CaseLine
(header
,code
) ->
283 conj_one testfn header
(statement_list testfn
mcode tail code
)
285 | Ast.OptCase
(case
) -> []
287 (* --------------------------------------------------------------------- *)
288 (* Function declaration *)
290 let top_level testfn
mcode t
: 'a list list
=
291 match Ast.unwrap t
with
292 Ast.FILEINFO
(old_file
,new_file
) -> failwith
"not supported fileinfo"
293 | Ast.DECL
(stmt
) -> statement testfn
mcode false stmt
294 | Ast.CODE
(stmt_dots
) -> statement_list testfn
mcode false stmt_dots
295 | Ast.ERRORWORDS
(exps
) -> failwith
"not supported errorwords"
297 (* --------------------------------------------------------------------- *)
302 (* if we end up with nothing, we assume that this rule is only here because
303 someone depends on it, and thus we try again with testfn as contains_modif.
304 Alternatively, we could check that this rule is mentioned in some
305 dependency, but that would be a little more work, and doesn't seem
308 (* lists are sorted such that smaller DisjRuleElem are first, because they
309 are cheaper to test *)
311 let asttomemberz (_
,_
,l
) used_after
=
312 let process_one (l
: (int * Ast_cocci.rule_elem) list list
) =
318 List.sort
(function (n1
,_
) -> function (n2
,_
) -> compare n1 n2
)
320 List.map
(function (_
,x
) -> (Lib_engine.Match
(x
),CTL.Control
)) info)
323 (function min
-> function (max
,big_max
) ->
327 [] -> process_one (big_max
())
328 | max
-> process_one max
)
329 | _
-> process_one min
)
330 (List.map
(top_level contains_constant no_mcode) l
)
333 (function x
-> function ua
-> function _
->
334 top_level (contains_modif ua
) mcode x
)
337 (function x
-> function _
->
338 top_level (function _
-> true) no_mcode x
)
341 let asttomember r used_after
=
343 Ast.ScriptRule _
| Ast.InitialScriptRule _
| Ast.FinalScriptRule _
-> []
344 | Ast.CocciRule
(a
,b
,c
,_
,_
) -> asttomemberz (a
,b
,c
) used_after