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.
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.
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.
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/>.
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
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.
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.
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.
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/>.
44 * The authors reserve the right to distribute this or future versions of
45 * Coccinelle under other licenses.
49 (* on the first pass, onlyModif is true, so we don't see all matched nodes,
52 module Ast
= Ast_cocci
53 module V
= Visitor_ast
56 let mcode r
(_
,_
,kind
,_
) =
58 Ast.MINUS
(_
,_
,_
,_
) -> true
59 | Ast.PLUS _
-> failwith
"not possible"
60 | Ast.CONTEXT
(_
,info
) -> not
(info
= Ast.NOTHING
)
62 let no_mcode _ _
= false
64 let contains_modif used_after x
=
65 if List.exists
(function x
-> List.mem x used_after
) (Ast.get_fvs x
)
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
=
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
80 V.combiner
bind option_default
81 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
83 do_nothing do_nothing do_nothing do_nothing do_nothing
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
88 (* contains an inherited metavariable or contains a constant *)
89 let contains_constant x
=
90 match Ast.get_inherited x
with
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
97 match Ast.unwrap i
with
101 match Ast.unwrap e
with
102 Ast.Constant
(const
) -> true
105 V.combiner
bind option_default
106 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
108 do_nothing do_nothing do_nothing do_nothing do_nothing
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
114 (* --------------------------------------------------------------------- *)
116 let print_info = function
117 [] -> Printf.printf
"no information\n"
121 Printf.printf
"one set of required things %d:\n"
124 (function (_
,thing
) ->
126 (Pretty_print_cocci.rule_elem_to_string thing
))
130 (* --------------------------------------------------------------------- *)
132 (* drop all distinguishing information from a term *)
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
) ->
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
))
148 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
149 do_nothing do_nothing do_nothing do_nothing do_nothing
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
155 (* --------------------------------------------------------------------- *)
157 let disj l1 l2
= l1 l2
170 let cur_res = (List.sort compare
(Common.union_set x cur
)) in
173 (function x
-> not
(Common.include_set
cur_res x
))
178 let conj_wrapped x l
= conj [List.map
(function x
-> (1,strip x
)) x
] l
180 (* --------------------------------------------------------------------- *)
181 (* the main translation loop *)
184 match Ast.unwrap re
with
185 Ast.DisjRuleElem
(res) -> [[(List.length
res,strip re
)]]
186 | _
-> [[(1,strip re
)]]
188 let conj_one testfn x l
=
190 then conj (rule_elem x
) l
193 let 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
202 conj (statement testfn
mcode false cur
) rest
)
203 rest
(statement testfn
mcode tail last
))
205 and statement testfn
mcode tail stmt
: 'a list list
=
206 match Ast.unwrap stmt
with
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 [])
212 | Ast.Seq
(lbrace
,body
,rbrace
) ->
213 let body_info = statement_list testfn
mcode tail body
in
214 if testfn lbrace
or testfn rbrace
215 then conj_wrapped [lbrace
;rbrace
] body_info
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
226 | Ast.Switch
(header
,lb
,decls
,cases
,rb
) ->
229 (statement_list testfn
mcode false decls
)
230 (case_lines testfn
mcode tail cases
) in
231 if testfn header
or testfn lb
or testfn rb
232 then conj (rule_elem header
) body_info
235 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,(_
,_
,_
,aft
)) ->
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
244 | Ast.Disj
(stmt_dots_list
) ->
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
250 else Common.union_all
processed
252 | Ast.Nest
(starter
,stmt_dots
,ender
,whencode
,true,_
,_
) ->
253 statement_list testfn
mcode false stmt_dots
255 | Ast.Nest
(starter
,stmt_dots
,ender
,whencode
,false,_
,_
) -> []
257 | Ast.Dots
(_
,whencodes
,_
,_
) -> []
259 | Ast.FunDecl
(header
,lbrace
,body
,rbrace
) ->
260 let body_info = statement_list testfn
mcode true body
in
261 if testfn header
or testfn lbrace
or testfn rbrace
262 then conj (rule_elem header
) body_info
265 | Ast.Define
(header
,body
) ->
266 conj_one testfn header
(statement_list testfn
mcode tail body
)
268 | Ast.OptStm
(stm
) -> []
270 | Ast.UniqueStm
(stm
) -> statement testfn
mcode tail stm
272 | _
-> failwith
"not supported"
274 and case_lines testfn
mcode tail cases
=
281 conj (case_line testfn
mcode false cur
) rest
)
282 rest
(case_line testfn
mcode tail last
)
284 and 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
)
289 | Ast.OptCase
(case
) -> []
291 (* --------------------------------------------------------------------- *)
292 (* Function declaration *)
294 let 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"
301 (* --------------------------------------------------------------------- *)
306 (* if we end up with nothing, we assume that this rule is only here because
307 someone depends on it, and thus we try again with testfn as contains_modif.
308 Alternatively, we could check that this rule is mentioned in some
309 dependency, but that would be a little more work, and doesn't seem
312 (* lists are sorted such that smaller DisjRuleElem are first, because they
313 are cheaper to test *)
315 let asttomemberz (_
,_
,l
) used_after
=
316 let process_one (l
: (int * Ast_cocci.rule_elem) list list
) =
322 List.sort
(function (n1
,_
) -> function (n2
,_
) -> compare n1 n2
)
324 List.map
(function (_
,x
) -> (Lib_engine.Match
(x
),CTL.Control
)) info)
327 (function min
-> function (max
,big_max
) ->
331 [] -> process_one (big_max
())
332 | max
-> process_one max
)
333 | _
-> process_one min
)
334 (List.map
(top_level contains_constant no_mcode) l
)
337 (function x
-> function ua
-> function _
->
338 top_level (contains_modif ua
) mcode x
)
341 (function x
-> function _
->
342 top_level (function _
-> true) no_mcode x
)
345 let asttomember r used_after
=
347 Ast.ScriptRule _
| Ast.InitialScriptRule _
| Ast.FinalScriptRule _
-> []
348 | Ast.CocciRule
(a
,b
,c
,_
,_
) -> asttomemberz (a
,b
,c
) used_after