2 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
3 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
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.
23 (* on the first pass, onlyModif is true, so we don't see all matched nodes,
26 module Ast
= Ast_cocci
27 module V
= Visitor_ast
30 let mcode r
(_
,_
,kind
,_
) =
32 Ast.MINUS
(_
,_
,_
,_
) -> true
33 | Ast.PLUS
-> failwith
"not possible"
34 | Ast.CONTEXT
(_
,info
) -> not
(info
= Ast.NOTHING
)
36 let no_mcode _ _
= false
38 let contains_modif used_after x
=
39 if List.exists
(function x
-> List.mem x used_after
) (Ast.get_fvs x
)
42 let bind x y
= x
or y
in
43 let option_default = false in
44 let do_nothing r k e
= k e
in
45 let rule_elem r k re
=
47 match Ast.unwrap re
with
48 Ast.FunHeader
(bef
,_
,fninfo
,name
,lp
,params
,rp
) ->
49 bind (mcode r
((),(),bef
,Ast.NoMetaPos
)) res
50 | Ast.Decl
(bef
,_
,decl
) ->
51 bind (mcode r
((),(),bef
,Ast.NoMetaPos
)) res
54 V.combiner
bind option_default
55 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
57 do_nothing do_nothing do_nothing do_nothing
58 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
59 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
60 recursor.V.combiner_rule_elem x
62 (* contains an inherited metavariable or contains a constant *)
63 let contains_constant x
=
64 match Ast.get_inherited x
with
66 let bind x y
= x
or y
in
67 let option_default = false in
68 let do_nothing r k e
= k e
in
69 let mcode _ _
= false in
71 match Ast.unwrap i
with
75 match Ast.unwrap e
with
76 Ast.Constant
(const
) -> true
79 V.combiner
bind option_default
80 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
82 do_nothing do_nothing do_nothing do_nothing
83 ident expr do_nothing do_nothing do_nothing do_nothing
84 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing in
85 recursor.V.combiner_rule_elem x
88 (* --------------------------------------------------------------------- *)
90 let print_info = function
91 [] -> Printf.printf
"no information\n"
95 Printf.printf
"one set of required things %d:\n"
98 (function (_
,thing
) ->
100 (Pretty_print_cocci.rule_elem_to_string thing
))
104 (* --------------------------------------------------------------------- *)
106 (* drop all distinguishing information from a term *)
108 let do_nothing r k e
= Ast.make_term
(Ast.unwrap
(k e
)) in
109 let do_absolutely_nothing r k e
= k e
in
110 let mcode m
= Ast.make_mcode
(Ast.unwrap_mcode m
) in
111 let rule_elem r k re
=
112 let res = do_nothing r k re
in
113 let no_mcode = Ast.CONTEXT
(Ast.NoPos
,Ast.NOTHING
) in
114 match Ast.unwrap
res with
115 Ast.FunHeader
(bef
,b
,fninfo
,name
,lp
,params
,rp
) ->
117 (Ast.FunHeader
(no_mcode,b
,fninfo
,name
,lp
,params
,rp
))
118 | Ast.Decl
(bef
,b
,decl
) -> Ast.rewrap
res (Ast.Decl
(no_mcode,b
,decl
))
122 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
123 do_nothing do_nothing do_nothing do_nothing
124 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
125 do_nothing rule_elem do_nothing do_nothing
126 do_nothing do_absolutely_nothing in
127 recursor.V.rebuilder_rule_elem
129 (* --------------------------------------------------------------------- *)
131 let disj l1 l2
= l1 l2
144 let cur_res = (List.sort compare
(Common.union_set x cur
)) in
147 (function x
-> not
(Common.include_set
cur_res x
))
152 let conj_wrapped x l
= conj [List.map
(function x
-> (1,strip x
)) x
] l
154 (* --------------------------------------------------------------------- *)
155 (* the main translation loop *)
158 match Ast.unwrap re
with
159 Ast.DisjRuleElem
(res) -> [[(List.length
res,strip re
)]]
160 | _
-> [[(1,strip re
)]]
162 let conj_one testfn x l
=
164 then conj (rule_elem x
) l
167 let rec statement_list testfn
mcode tail stmt_list
: 'a list list
=
168 match Ast.unwrap stmt_list
with
169 Ast.DOTS
(x
) | Ast.CIRCLES
(x
) | Ast.STARS
(x
) ->
170 (match List.rev x
with
176 conj (statement testfn
mcode false cur
) rest
)
177 rest
(statement testfn
mcode tail last
))
179 and statement testfn
mcode tail stmt
: 'a list list
=
180 match Ast.unwrap stmt
with
182 (match Ast.unwrap ast
with
183 (* modifications on return are managed in some other way *)
184 Ast.Return
(_
,_
) | Ast.ReturnExpr
(_
,_
,_
) when tail
-> []
185 | _
-> if testfn ast
then rule_elem ast
else [])
186 | Ast.Seq
(lbrace
,body
,rbrace
) ->
187 let body_info = statement_list testfn
mcode tail body
in
188 if testfn lbrace
or testfn rbrace
189 then conj_wrapped [lbrace
;rbrace
] body_info
192 | Ast.IfThen
(header
,branch
,(_
,_
,_
,aft
))
193 | Ast.While
(header
,branch
,(_
,_
,_
,aft
))
194 | Ast.For
(header
,branch
,(_
,_
,_
,aft
))
195 | Ast.Iterator
(header
,branch
,(_
,_
,_
,aft
)) ->
196 if testfn header
or mcode () ((),(),aft
,Ast.NoMetaPos
)
197 then conj (rule_elem header
) (statement testfn
mcode tail branch
)
198 else statement testfn
mcode tail branch
200 | Ast.Switch
(header
,lb
,cases
,rb
) ->
201 let body_info = case_lines testfn
mcode tail cases
in
202 if testfn header
or testfn lb
or testfn rb
203 then conj (rule_elem header
) body_info
206 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,(_
,_
,_
,aft
)) ->
209 (statement testfn
mcode tail branch1
)
210 (statement testfn
mcode tail branch2
) in
211 if testfn ifheader
or mcode () ((),(),aft
,Ast.NoMetaPos
)
212 then conj (rule_elem ifheader
) branches
215 | Ast.Disj
(stmt_dots_list
) ->
217 List.map
(statement_list testfn
mcode tail
) stmt_dots_list
in
218 (* if one branch gives no information, then we have to take anything *)
219 if List.exists
(function [] -> true | _
-> false) processed
221 else Common.union_all
processed
223 | Ast.Nest
(stmt_dots
,whencode
,true,_
,_
) ->
224 statement_list testfn
mcode false stmt_dots
226 | Ast.Nest
(stmt_dots
,whencode
,false,_
,_
) -> []
228 | Ast.Dots
(_
,whencodes
,_
,_
) -> []
230 | Ast.FunDecl
(header
,lbrace
,body
,rbrace
) ->
231 let body_info = statement_list testfn
mcode true body
in
232 if testfn header
or testfn lbrace
or testfn rbrace
233 then conj (rule_elem header
) body_info
236 | Ast.Define
(header
,body
) ->
237 conj_one testfn header
(statement_list testfn
mcode tail body
)
239 | Ast.OptStm
(stm
) -> []
241 | Ast.UniqueStm
(stm
) -> statement testfn
mcode tail stm
243 | _
-> failwith
"not supported"
245 and case_lines testfn
mcode tail cases
=
252 conj (case_line testfn
mcode false cur
) rest
)
253 rest
(case_line testfn
mcode tail last
)
255 and case_line testfn
mcode tail case
=
256 match Ast.unwrap case
with
257 Ast.CaseLine
(header
,code
) ->
258 conj_one testfn header
(statement_list testfn
mcode tail code
)
260 | Ast.OptCase
(case
) -> []
262 (* --------------------------------------------------------------------- *)
263 (* Function declaration *)
265 let top_level testfn
mcode t
: 'a list list
=
266 match Ast.unwrap t
with
267 Ast.FILEINFO
(old_file
,new_file
) -> failwith
"not supported fileinfo"
268 | Ast.DECL
(stmt
) -> statement testfn
mcode false stmt
269 | Ast.CODE
(stmt_dots
) -> statement_list testfn
mcode false stmt_dots
270 | Ast.ERRORWORDS
(exps
) -> failwith
"not supported errorwords"
272 (* --------------------------------------------------------------------- *)
277 (* if we end up with nothing, we assume that this rule is only here because
278 someone depends on it, and thus we try again with testfn as contains_modif.
279 Alternatively, we could check that this rule is mentioned in some
280 dependency, but that would be a little more work, and doesn't seem
283 (* lists are sorted such that smaller DisjRuleElem are first, because they
284 are cheaper to test *)
286 let asttomemberz (_
,_
,l
) used_after
=
287 let process_one (l
: (int * Ast_cocci.rule_elem) list list
) =
293 List.sort
(function (n1
,_
) -> function (n2
,_
) -> compare n1 n2
)
295 List.map
(function (_
,x
) -> (Lib_engine.Match
(x
),CTL.Control
)) info)
298 (function min
-> function (max
,big_max
) ->
302 [] -> process_one (big_max
())
303 | max
-> process_one max
)
304 | _
-> process_one min
)
305 (List.map
(top_level contains_constant no_mcode) l
)
308 (function x
-> function ua
-> function _
->
309 top_level (contains_modif ua
) mcode x
)
312 (function x
-> function _
->
313 top_level (function _
-> true) no_mcode x
)
316 let asttomember r used_after
=
318 Ast.ScriptRule _
| Ast.InitialScriptRule _
| Ast.FinalScriptRule _
-> []
319 | Ast.CocciRule
(a
,b
,c
,_
,_
) -> asttomemberz (a
,b
,c
) used_after